Skip to content

Commit

Permalink
#7: Move the code from atum-service into this repository (#10)
Browse files Browse the repository at this point in the history
* moved the code
* added code description and enhanced `README.md`
* fixed for Scala 2.13

---------

Co-authored-by: miroslavpojer <miroslav.pojer@absa.africa>
  • Loading branch information
benedeki and miroslavpojer authored Dec 8, 2023
1 parent 3d274b3 commit 8778d5f
Show file tree
Hide file tree
Showing 21 changed files with 1,358 additions and 3 deletions.
34 changes: 34 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#
# Copyright 2023 ABSA Group Limited
#
# Licensed 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.

# top-most EditorConfig file
root = true

[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true

[*.{java,scala,js,json,css}]
indent_size = 2
indent_style = space
insert_final_newline = true
max_line_length = 120

[*.md]
trim_trailing_whitespace = false

[*.{cmd,bat}]
end_of_line = crlf
insert_final_newline = true
28 changes: 28 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#
# Copyright 2023 ABSA Group Limited
#
# Licensed 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.

###############################
# Git Line Endings #
###############################

# Set default behaviour to automatically normalize line endings.
* text=auto

# Force the following filetypes to have unix eols, Windows can usually handle it well
*.* text eol=lf

# Force batch scripts to always use CRLF line endings as they in some cases might not work correctly.
# Also if a repo is accessed in Windows via a file share from Linux, the scripts will work too
*.cmd text eol=crlf
*.bat text eol=crlf
2 changes: 1 addition & 1 deletion .github/workflows/assign_issue_to_project.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright 2021 ABSA Group Limited
# Copyright 2023 ABSA Group Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dependent_items.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright 2021 ABSA Group Limited
# Copyright 2023 ABSA Group Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down
54 changes: 54 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#
# Copyright 2023 ABSA Group Limited
#
# Licensed 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.
#
# use glob syntax.
syntax: glob
*.ser
*.class
*~
*.bak
#*.off
*.old

# eclipse conf file
.settings
.classpath
.project
.manager
.scala_dependencies
.scalastyle

# idea
.idea
*.iml

# vs code
.vscode

# building
target
build
null
tmp*
temp*
dist
test-output
build.log

# other scm
.svn
.CVS
.hg*

.bsp
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,22 @@
# balta
# Balta

Scala library to write Postgres DB code tests with

Balta is a Scala library to help creating database tests, particularly testing Database functions. It is based on the
popular [ScalaTest](http://www.scalatest.org/) library and uses [PostgreSQL](https://www.postgresql.org/) as the
database engine.

It's a natural complement to the use of [Fa-Db library](https://github.com/AbsaOSS/fa-db) in applications.

## Expected test-case structure
1. _Transaction start_*
2. Insert needed data into tables
3. Call the function to be tested
4. Verify the return values of the function via the `verify` function provided
5. Verify the data un the tables
6. _Transaction rollback_*

* The transaction start and rollback are done automatically before or after the execution respectively of the `test` function provided

Advantages of this approach is that the tests repeateble, they are isolated from each other and the database is always
in a known state before and after each test.
172 changes: 172 additions & 0 deletions balta/src/main/scala/za/co/absa/balta/DBTestSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/*
* Copyright 2023 ABSA Group Limited
*
* Licensed 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.
*/

package za.co.absa.balta

import org.scalactic.source
import org.scalatest.Tag
import org.scalatest.funsuite.AnyFunSuite
import za.co.absa.balta.classes.DBFunction.DBFunctionWithPositionedParamsOnly
import za.co.absa.balta.classes.setter.{AllowedParamTypes, Params}
import za.co.absa.balta.classes.setter.Params.{NamedParams, OrderedParams}
import za.co.absa.balta.classes.{ConnectionInfo, DBConnection, DBFunction, DBTable, QueryResult}

import java.sql.DriverManager
import java.time.OffsetDateTime
import java.util.Properties

/**
* This is a base class for all DB tests. It inherits from AnyFunSuite and provides the following:
* * automatic creation and provision of a DB connection
* * an enhanced test function that automatically rolls back the transaction after the test is finished
* * easy access to DB tables and functions
* * the now() function that returns the current transaction time in the DB
*/
abstract class DBTestSuite extends AnyFunSuite {

/* the DB connection is ``lazy`, so it actually can be created only when needed and therefore the credentials
overridden in the successor */
protected lazy implicit val dbConnection: DBConnection = {
createConnection(
connectionInfo.dbUrl,
connectionInfo.username,
connectionInfo.password
)
}

/**
* This is the connection info for the DB. It can be overridden in the derived classes to provide specific credentials
*/
protected lazy val connectionInfo: ConnectionInfo = readConnectionInfoFromConfig

/**
* This is an enhanced test function that automatically rolls back the transaction after the test is finished
*
* @param testName – the name of the test
* @param testTags – the optional list of tags for this test
* @param testFun – the test function
*/
override protected def test(testName: String, testTags: Tag*)
(testFun: => Any /* Assertion */)
(implicit pos: source.Position): Unit = {
val dbTestFun = {
try {
testFun
}
finally {
if (connectionInfo.persistData) {
dbConnection.connection.commit()
} else {
dbConnection.connection.rollback()
}
}
}
super.test(testName, testTags: _*)(dbTestFun)
}

/**
* This is a helper function that allows to easily access a DB table
* @param tableName - the name of the table
* @return - the DBTable object
*/
protected def table(tableName: String): DBTable = {
DBTable(tableName)
}

/**
* This is a helper function that allows to easily access a DB function
* @param functionName - the name of the function
* @return - the DBFunction object
*/
protected def function(functionName: String): DBFunctionWithPositionedParamsOnly = {
DBFunction(functionName)
}

/**
* This is a helper function that allows to easily get the DB current time
* @param connection - the DB connection
* @return - the current transaction time
*/
protected def now()(implicit connection: DBConnection): OffsetDateTime = {
val preparedStatement = connection.connection.prepareStatement("SELECT now() AS now")
val prep = preparedStatement.executeQuery()
val result = new QueryResult(prep).next().getOffsetDateTime("now").get
prep.close()
result
}

/**
* This is a helper function that allows to easily create parameter for table and function queries
*
* @param paramName - the name of the parameter
* @param value - the value of the parameter
* @tparam T - the type of the parameter value
* @return - a list parameters to be used in an SQL prepared statement
*/
protected def add[T: AllowedParamTypes](paramName: String, value: T): NamedParams = {
Params.add(paramName, value)
}

/**
* This is a helper function that allows to easily create parameter of value NULL for table and function queries
*
* @param paramName - the name of the parameter
* @return - a list parameters to be used in an SQL prepared statement
*/
protected def addNull(paramName: String): NamedParams = {
Params.addNull(paramName)
}

/**
* This is a helper function that allows to easily create a positioned parameter for table and function queries
*
* @param value - the value of the parameter
* @tparam T - the type of the parameter value
* @return - a list parameters to be used in an SQL prepared statement
*/
protected def add[T: AllowedParamTypes](value: T): OrderedParams = {
Params.add(value)
}

/**
* This is a helper function that allows to easily create a positioned parameter of value NULL for table and function queries
*
* @tparam T - the type of the parameter value
* @return - a list parameters to be used in an SQL prepared statement
*/
protected def addNull[T: AllowedParamTypes](): OrderedParams = {
Params.addNull()
}

// private functions
private def createConnection(url: String, username: String, password: String): DBConnection = {
val conn = DriverManager.getConnection(url, username, password)
conn.setAutoCommit(false)
new DBConnection(conn)
}

private def readConnectionInfoFromConfig = {
val properties = new Properties()
properties.load(getClass.getResourceAsStream("/database.properties"))

ConnectionInfo(
dbUrl = properties.getProperty("test.jdbc.url"),
username = properties.getProperty("test.jdbc.username"),
password = properties.getProperty("test.jdbc.password"),
persistData = properties.getProperty("test.persist.db", "false").toBoolean
)
}
}
Loading

0 comments on commit 8778d5f

Please sign in to comment.