Skip to content

Commit

Permalink
Add XA transaction testcases
Browse files Browse the repository at this point in the history
  • Loading branch information
niveathika committed Nov 11, 2022
1 parent 4e683f1 commit c5e956f
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 12 deletions.
27 changes: 15 additions & 12 deletions ballerina/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -221,23 +221,26 @@ task startTestDockerContainers() {
}
}

task stopTestDockerContainers() {
doLast {
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
def containers = "ballerina-oracledb"
try {
def stdOut = new ByteArrayOutputStream()
exec {
commandLine 'sh', '-c', "docker stop ${containers}"
standardOutput = stdOut
}
} catch (ignore) {
println("Gradle process can safely ignore stopTestDockerContainers task")
def stopTestDockerContainer(containerName) {
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
try {
def stdOut = new ByteArrayOutputStream()
exec {
commandLine 'sh', '-c', "docker stop ${containerName}"
standardOutput = stdOut
}
} catch (ignore) {
println("Gradle process can safely ignore stopTestDockerContainers task")
}
}
}

task stopTestDockerContainers() {
doLast {
stopTestDockerContainer("ballerina-oracledb")
}
}

updateTomlFiles.dependsOn copyStdlibs
startTestDockerContainers.dependsOn createTestDockerImage

Expand Down
166 changes: 166 additions & 0 deletions ballerina/tests/15-xa-transaction.bal
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Copyright (c) 2022 WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
//
// WSO2 LLC. licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except
// in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import ballerina/test;
import ballerina/sql;

int DBCLIENT2_PORT = 1522;

type XAResultCount record {
int COUNTVAL;
};

// Following test cases are disabled, since they need 2 db instances to run.
// Due to a constraint 2 Oracle Docker containers cannot be run on the same machine.
// Currently verified it manually with a local instance running on port 1522 and docker image running on port 1521

@test:Config {
enable: false,
groups: ["transaction", "xa-transaction"]
}
function testXATransactionSuccess() returns error? {
Client dbClient1 = check new (HOST, USER, PASSWORD, DATABASE, PORT, connectionPool = {maxOpenConnections: 1},
options = {
useXADatasource: true
}
);
Client dbClient2 = check new (HOST, USER, PASSWORD, DATABASE, DBCLIENT2_PORT, connectionPool = {maxOpenConnections: 1},
options = {
useXADatasource: true
}
);

transaction {
_ = check dbClient1->execute(`insert into Customers (customerId, name, creditLimit, country)
values (1, 'Anne', 1000, 'UK')`);
_ = check dbClient2->execute(`insert into Salary (id, value) values (1, 1000)`);
check commit;
} on fail error e {
test:assertFail(msg = "Transaction failed" + e.message());
}

int count1 = check getCustomerCount(dbClient1, 1);
int count2 = check getSalaryCount(dbClient2, 1);
test:assertEquals(count1, 1, "First transaction failed");
test:assertEquals(count2, 1, "Second transaction failed");

check dbClient1.close();
check dbClient2.close();
}

@test:Config {
enable: false,
groups: ["transaction", "xa-transaction"]
}
function testXATransactionFailureWithDataSource() returns error? {
Client dbClient1 = check new (HOST, USER, PASSWORD, DATABASE, PORT, connectionPool = {maxOpenConnections: 1},
options = {
useXADatasource: true
}
);
Client dbClient2 = check new (HOST, USER, PASSWORD, DATABASE, DBCLIENT2_PORT, connectionPool = {maxOpenConnections: 1},
options = {
useXADatasource: true
}
);

transaction {
// Intentionally fail first statement
_ = check dbClient1->execute(`insert into CustomersTrx (customerId, name, creditLimit, country)
values (30, 'Anne', 1000, 'UK')`);
_ = check dbClient2->execute(`insert into Salary (id, value) values (10, 1000)`);
check commit;
} on fail error e {
test:assertTrue(e.message().includes("Duplicate"), msg = "Transaction failed as expected");
}

int count1 = check getCustomerTrxCount(dbClient1, 30);
int count2 = check getSalaryCount(dbClient2, 20);
test:assertEquals(count1, 1, "First transaction should have failed");
test:assertEquals(count2, 0, "Second transaction should not have been executed");

check dbClient1.close();
check dbClient2.close();
}

@test:Config {
enable: false,
groups: ["transaction", "xa-transaction"]
}
function testXATransactionPartialSuccessWithDataSource() returns error? {
Client dbClient1 = check new (HOST, USER, PASSWORD, DATABASE, PORT, connectionPool = {maxOpenConnections: 1},
options = {
useXADatasource: true
}
);
Client dbClient2 = check new (HOST, USER, PASSWORD, DATABASE, DBCLIENT2_PORT, connectionPool = {maxOpenConnections: 1},
options = {
useXADatasource: true
}
);

transaction {
_ = check dbClient1->execute(`insert into Customers (customerId, name, creditLimit, country)
values (30, 'Anne', 1000, 'UK')`);
// Intentionally fail second statement
_ = check dbClient2->execute(`insert into SalaryTrx (id, value) values (20, 1000)`);
check commit;
} on fail error e {
test:assertTrue(e.message().includes("Duplicate"), msg = "Transaction failed as expected");
}

int count1 = check getCustomerCount(dbClient1, 30);
int count2 = check getSalaryTrxCount(dbClient2, 20);
test:assertEquals(count1, 0, "First transaction is not rolledback");
test:assertEquals(count2, 1, "Second transaction has succeeded");

check dbClient1.close();
check dbClient2.close();
}

isolated function getCustomerCount(Client dbClient, int id) returns int|error {
stream<XAResultCount, sql:Error?> streamData = dbClient->query(`Select COUNT(*) as
countVal from Customers where customerId = ${id}`);
return getResult(streamData);
}

isolated function getCustomerTrxCount(Client dbClient, int id) returns int|error {
stream<XAResultCount, sql:Error?> streamData = dbClient->query(`Select COUNT(*) as
countVal from CustomersTrx where customerId = ${id}`);
return getResult(streamData);
}

isolated function getSalaryCount(Client dbClient, int id) returns int|error {
stream<XAResultCount, sql:Error?> streamData = dbClient->query(`Select COUNT(*) as countval
from Salary where id = ${id}`);
return getResult(streamData);
}

isolated function getSalaryTrxCount(Client dbClient, int id) returns int|error {
stream<XAResultCount, sql:Error?> streamData = dbClient->query(`Select COUNT(*) as countval
from SalaryTrx where id = ${id}`);
return getResult(streamData);
}

isolated function getResult(stream<XAResultCount, sql:Error?> streamData) returns int|error {
record {|XAResultCount value;|}? data = check streamData.next();
check streamData.close();
XAResultCount? value = data?.value;
if value is XAResultCount {
return value.COUNTVAL;
}
return 0;
}
2 changes: 2 additions & 0 deletions ballerina/tests/resources/sql-scripts/run-sql-scripts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ sqlplus -S admin/password@localhost/ORCLCDB.localdomain <<< @procedures/stored-p
sqlplus -S admin/password@localhost/ORCLCDB.localdomain <<< @query/complex-params-test-data.sql
sqlplus -S admin/password@localhost/ORCLCDB.localdomain <<< @query/simple-params-test-data.sql
sqlplus -S admin/password@localhost/ORCLCDB.localdomain <<< @transaction/local-transaction-test-data.sql
sqlplus -S admin/password@localhost/ORCLCDB.localdomain <<< @transaction/xa-transaction-test-data-1.sql
sqlplus -S admin/password@localhost/ORCLCDB.localdomain <<< @transaction/xa-transaction-test-data-2.sql
sqlplus -S admin/password@localhost/ORCLCDB.localdomain <<< @error/error-test-data.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
CREATE TABLE Customers(
customerId NUMBER,
name VARCHAR(300),
creditLimit DOUBLE PRECISION,
country VARCHAR(300)
);

CREATE TABLE CustomersTrx(
customerId INTEGER,
name VARCHAR(300),
creditLimit DOUBLE PRECISION,
country VARCHAR(300),
PRIMARY KEY (customerId)
);

INSERT INTO CustomersTrx VALUES (30, 'Oliver', 200000, 'UK');
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CREATE TABLE Salary (
ID INTEGER,
VALUE DOUBLE PRECISION
);

CREATE TABLE SalaryTrx (
ID INTEGER,
VALUE DOUBLE PRECISION,
PRIMARY KEY (ID)
);

INSERT INTO SalaryTrx VALUES (20, 30000);

0 comments on commit c5e956f

Please sign in to comment.