Skip to content

Commit

Permalink
Feature/8 implement methods (#27)
Browse files Browse the repository at this point in the history
#8 - Implement method ideas
* Implemented full expected methods for Log 'ResponseAction'.
* Updated log message to keep same format - on debug level.
* Migrate several Set to Seq to keep order of elements which is required by logic of test design.
* Introduces Enums instead of constants.
* Make response perform methods private.
* Review of code warnings.
* Remove no more used object LoggerConfig.
* Remove no more used class and object TestResults.scala.
* Rename of variable in code to fit to real usage.
* Move Factory classes to dedicated package.
* Moved Suite related models classes to new suite package in model package.
* Rename Suite to TestSet.
* Rename SuiteAround to SuitePreAndPostProcessing.
* Rename SuiteBefore to BeforeTestSet
* Rename SuiteAfter to AfterTestSet
* Rename SuiteBundle to Suite
* Rename ResponsePerformer to ResponseActions
* Move ResponseAction related file into new package action
* Rename "endpoint" to "name" as this parameters is used as name for suite not as endpoint.
* Log action methods returns Unit.
* Remove usage of Success from Action implementations.
* Rename and move Type to String implicit conversion as they are used only in tests.
* Fix correct usage clue calls in assert (not assertEquals) method.
* Fix - Apply Scala CamelCase to enumeration contants.
  • Loading branch information
miroslavpojer authored Nov 3, 2023
1 parent bd0ad01 commit 03dca9c
Show file tree
Hide file tree
Showing 69 changed files with 2,062 additions and 1,065 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci-check-jacoco.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
min-coverage-changed-files: 80.0
title: JaCoCo code coverage report - ScAPI
update-comment: true
debug-mode: true
- name: Get the Coverage info
run: |
echo "Total coverage ${{ steps.jacoco.outputs.coverage-overall }}"
Expand Down
2 changes: 2 additions & 0 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ object Dependencies {
private val commonsIoVersion = "2.13.0"
private val requestsVersion = "0.8.0"
private val loggerVersion = "2.14.1"
private val scalaXmlVersion = "1.3.0"

def getScalaDependency(scalaVersion: String): ModuleID = "org.scala-lang" % "scala-library" % scalaVersion

Expand All @@ -40,6 +41,7 @@ object Dependencies {
"com.lihaoyi" %% "requests" % requestsVersion,
"org.apache.logging.log4j" % "log4j-core" % loggerVersion,
"org.apache.logging.log4j" % "log4j-api" % loggerVersion,
"org.scala-lang.modules" %% "scala-xml" % scalaXmlVersion,

// test
"org.scalameta" %% "munit" % munitVersion % Test
Expand Down
2 changes: 1 addition & 1 deletion testApi/src/main/resources/schema/after.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
"properties": {
"method": {
"type": "string",
"enum": ["assert.status-code", "assert.body-contains", "log.info", "extractJson.string-from-list"],
"enum": ["assert.response-time-is-below", "assert.response-time-is-above", "assert.status-code-equals", "assert.status-code-is-success", "assert.status-code-is-client-error", "assert.status-code-is-server-error", "assert.header-exists", "assert.header-value-equals", "assert.content-type-is-json", "assert.content-type-is-xml", "assert.content-type-is-html", "assert.cookie-exists", "assert.cookie-value-equals", "assert.cookie-is-secured", "assert.cookie-is-not-secured", "assert.body-contains-text", "log.error", "log.warn", "log.info", "log.debug", "extractJson.string-from-list"],
"description": "The method to be used for the response action. Restricted to specific values."
}
},
Expand Down
2 changes: 1 addition & 1 deletion testApi/src/main/resources/schema/before.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
"properties": {
"method": {
"type": "string",
"enum": ["assert.status-code", "assert.body-contains", "log.info", "extractJson.string-from-list"],
"enum": ["assert.response-time-is-below", "assert.response-time-is-above", "assert.status-code-equals", "assert.status-code-is-success", "assert.status-code-is-client-error", "assert.status-code-is-server-error", "assert.header-exists", "assert.header-value-equals", "assert.content-type-is-json", "assert.content-type-is-xml", "assert.content-type-is-html", "assert.cookie-exists", "assert.cookie-value-equals", "assert.cookie-is-secured", "assert.cookie-is-not-secured", "assert.body-contains-text", "log.error", "log.warn", "log.info", "log.debug", "extractJson.string-from-list"],
"description": "The method to be used for the response action."
}
},
Expand Down
12 changes: 6 additions & 6 deletions testApi/src/main/resources/schema/suite.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
"type": "object",
"additionalProperties": true,
"properties": {
"endpoint": {
"name": {
"type": "string",
"description": "The user endpoint name which suite cover by tests."
"description": "The suite name."
},
"tests": {
"type": "array",
Expand All @@ -20,7 +20,7 @@
}
},
"required": [
"endpoint",
"name",
"tests"
],
"title": "suite",
Expand Down Expand Up @@ -133,7 +133,7 @@
"properties": {
"method": {
"type": "string",
"enum": ["assert.status-code", "assert.body-contains", "log.info", "extractJson.string-from-list"],
"enum": ["assert.response-time-is-below", "assert.response-time-is-above", "assert.status-code-equals", "assert.status-code-is-success", "assert.status-code-is-client-error", "assert.status-code-is-server-error", "assert.header-exists", "assert.header-value-equals", "assert.content-type-is-json", "assert.content-type-is-xml", "assert.content-type-is-html", "assert.cookie-exists", "assert.cookie-value-equals", "assert.cookie-is-secured", "assert.cookie-is-not-secured", "assert.body-contains-text", "log.error", "log.warn", "log.info", "log.debug", "extractJson.string-from-list"],
"description": "The method to be used for the response action."
}
},
Expand All @@ -156,7 +156,7 @@
{
"properties": {
"method": {
"const": "assert.status-code"
"const": "assert.status-code-equals"
}
},
"required": ["code"]
Expand Down Expand Up @@ -190,7 +190,7 @@
{
"properties": {
"method": {
"const": "assert.status-code"
"const": "assert.status-code-equals"
}
}
},
Expand Down
23 changes: 15 additions & 8 deletions testApi/src/main/scala/africa/absa/testing/scapi/Exceptions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,30 @@ import com.networknt.schema.ValidationMessage

import scala.collection.mutable

case class UndefinedConstantsInProperties(undefinedConstants: Set[String], source: String)
case class UndefinedConstantsInPropertiesException(undefinedConstants: Set[String], source: String)
extends Exception(s"Undefined constant(s): '${undefinedConstants.mkString(", ")}' in '$source'.")

case class PropertyNotFound(property: String) extends Exception(s"Property not found: '$property'.")
case class PropertyNotFoundException(property: String) extends Exception(s"Property not found: '$property'.")

case class JsonInvalidSchema(filePath: String, messages: mutable.Set[ValidationMessage])
case class JsonInvalidSchemaException(filePath: String, messages: mutable.Set[ValidationMessage])
extends Exception(s"Json file '$filePath' not valid to defined json schema. " + messages.mkString("\n"))

case class ProjectLoadFailed() extends Exception("Problems during project loading.")
case class ProjectLoadFailedException() extends Exception("Problems during project loading.")

case class SuiteLoadFailed(detail: String) extends Exception(s"Problems during project loading. Details: $detail")
case class SuiteLoadFailedException(detail: String)
extends Exception(s"Problems during project loading. Details: $detail")

case class UndefinedHeaderType(undefinedType: String)
case class SuiteBeforeFailedException(detail: String)
extends Exception(s"Problems during running before suite logic. Details: $detail")

case class UndefinedHeaderTypeException(undefinedType: String)
extends Exception(s"Undefined Header content type: '$undefinedType'")

case class UndefinedResponseActionType(undefinedType: String)
case class UndefinedResponseActionTypeException(undefinedType: String)
extends Exception(s"Undefined response action content type: '$undefinedType'")

case class ContentValidationFailed(value: String, message: String)
case class ContentValidationFailedException(value: String, message: String)
extends Exception(s"Content validation failed for value: '$value': $message")

case class AssertionException(message: String)
extends Exception(s"Assertion failed: $message")
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
package africa.absa.testing.scapi

import africa.absa.testing.scapi.config.ScAPIRunnerConfig
import africa.absa.testing.scapi.json.{Environment, EnvironmentFactory, SuiteFactory}
import africa.absa.testing.scapi.json.factory.{EnvironmentFactory, SuiteFactory}
import africa.absa.testing.scapi.json.Environment
import africa.absa.testing.scapi.logging.Logger
import africa.absa.testing.scapi.model.{SuiteBundle, SuiteResults}
import africa.absa.testing.scapi.model.suite.{Suite, SuiteResult}
import africa.absa.testing.scapi.reporter.StdOutReporter
import africa.absa.testing.scapi.rest.RestClient
import africa.absa.testing.scapi.rest.request.sender.ScAPIRequestSender
Expand Down Expand Up @@ -47,20 +48,20 @@ object ScAPIRunner {
Logger.setLevel(if (cmd.debug) Level.DEBUG else Level.INFO)
cmd.logConfigInfo()

if (!Files.exists(Paths.get(cmd.testRootPath, "suites"))) throw SuiteLoadFailed("'suites' directory have to exist in project root.")
if (!Files.exists(Paths.get(cmd.testRootPath, "suites"))) throw SuiteLoadFailedException("'suites' directory have to exist in project root.")

// jsons to objects
val environment: Environment = EnvironmentFactory.fromFile(cmd.envPath)
val suiteBundles: Set[SuiteBundle] = SuiteFactory.fromFiles(environment, cmd.testRootPath, cmd.filter, cmd.fileFormat)
val suiteBundles: Set[Suite] = SuiteFactory.fromFiles(environment, cmd.testRootPath, cmd.filter, cmd.fileFormat)
SuiteFactory.validateSuiteContent(suiteBundles)

// run tests and result reporting - use categories for test filtering
if (cmd.validateOnly) {
Logger.info("Validate only => end run.")
} else {
Logger.info("Running tests")
val testResults: List[SuiteResults] = SuiteRunner.runSuites(suiteBundles, environment, () => new RestClient(ScAPIRequestSender))
StdOutReporter.printReport(testResults)
val suiteResults: List[SuiteResult] = SuiteRunner.runSuites(suiteBundles, environment, () => new RestClient(ScAPIRequestSender))
StdOutReporter.printReport(suiteResults)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,23 +115,23 @@ object ScAPIRunnerConfig {
opt[String]("filter")
.optional()
.action((value, config) => { config.copy(filter = value) })
.text(s"Filter rule to select test definitions file (recursive) to include into test suite. Default is all '${DefaultFilter}'")
.text(s"Filter rule to select test definitions file (recursive) to include into test suite. Default is all '$DefaultFilter'")

opt[Seq[String]]("categories")
.optional()
.valueName("<v1>,<v2>")
.action((value, config) => { config.copy(categories = value.toSet) })
.text(s"Select which test categories will be included into test suite. Default is all '${DefaultCategories}'")
.text(s"Select which test categories will be included into test suite. Default is all '$DefaultCategories'")

opt[Int]("thread-count")
.optional()
.action((value, config) => { config.copy(threadCount = value) })
.text(s"Maximum count of thread used to run test suite. Default is '${DefaultThreadCount}'")
.text(s"Maximum count of thread used to run test suite. Default is '$DefaultThreadCount'")

opt[String]("file-format")
.optional()
.action((value, config) => { config.copy(fileFormat = value) })
.text(s"Format of definition files. Default is all '${DefaultFileFormat}'")
.text(s"Format of definition files. Default is all '$DefaultFileFormat'")

opt[String]("report")
.optional()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@

package africa.absa.testing.scapi.json

import africa.absa.testing.scapi.rest.response.action.types.ResponseActionGroupType.ResponseActionGroupType
import africa.absa.testing.scapi.utils.cache.RuntimeCache
import africa.absa.testing.scapi.{PropertyNotFound, UndefinedConstantsInProperties}
import africa.absa.testing.scapi.{PropertyNotFoundException, UndefinedConstantsInPropertiesException}

import scala.util.matching.Regex

Expand Down Expand Up @@ -56,10 +57,10 @@ sealed protected trait ReferenceResolver {
* If there are any unresolved references, it throws an exception.
*
* @param notResolvedReferences A set of unresolved reference keys.
* @throws UndefinedConstantsInProperties If there are any unresolved references.
* @throws UndefinedConstantsInPropertiesException If there are any unresolved references.
*/
private def notResolved(notResolvedReferences: Set[String]): Unit =
if (notResolvedReferences.nonEmpty) throw UndefinedConstantsInProperties(notResolvedReferences, s"'${getClass.getSimpleName}' action.")
if (notResolvedReferences.nonEmpty) throw UndefinedConstantsInPropertiesException(notResolvedReferences, s"'${getClass.getSimpleName}' action.")

/**
* Resolve a map of references to their actual values. It iteratively updates the map with resolved values.
Expand Down Expand Up @@ -114,7 +115,7 @@ case class Environment private(constants: Map[String, String], properties: Map[S
* @param key The key to retrieve the value for.
* @return The value corresponding to the key.
*/
def apply(key: String): String = properties.getOrElse(key, constants.getOrElse(key, throw PropertyNotFound(key)))
def apply(key: String): String = properties.getOrElse(key, constants.getOrElse(key, throw PropertyNotFoundException(key)))

/**
* Method to resolve all the references in the environment's properties.
Expand Down Expand Up @@ -198,23 +199,20 @@ case class Action private(methodName: String, url: String, body: Option[String]
}

/**
* Case class that represents ResponseAction.
* This class is used to hold test response action.
* It implements the `ReferenceResolver` trait to support resolution of reference constants.
* Represents a `ResponseAction` case class.
*
* <p>This class encapsulates the details of a test response action and provides
* functionality to resolve reference constants through the `ReferenceResolver` trait.</p>
*
* @constructor create a new ResponseAction with a name and value.
* @param method the "group and name" of the response action.
* @param params the map containing the parameters of the response action. Each key-value pair in the map
* represents a parameter name and its corresponding value.
* @param group The type of the response action group.
* @param name The name that identifies the response action.
* @param params A map containing the parameters of the response action. Each entry in the map
* corresponds to a parameter name and its associated value.
*/
case class ResponseAction private(method: String,
case class ResponseAction private(group: ResponseActionGroupType,
name: String,
params: Map[String, String]) extends ReferenceResolver {

private def splitter: Seq[String] = method.split("\\.").toSeq

def group : String = splitter.head
def name : String = splitter.tail.head

/**
* Method to resolve references.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ package africa.absa.testing.scapi.json
trait Requestable {
def name: String

def headers: Set[Header]
def headers: Seq[Header]

def actions: Set[Action]
def actions: Seq[Action]

def responseActions: Set[ResponseAction]
def responseActions: Seq[ResponseAction]
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
* limitations under the License.
*/

package africa.absa.testing.scapi.json
package africa.absa.testing.scapi.json.factory

import africa.absa.testing.scapi.json.Environment
import africa.absa.testing.scapi.json.schema.{JsonSchemaValidator, ScAPIJsonSchema}
import africa.absa.testing.scapi.utils.file.JsonUtils
import spray.json._
Expand Down
Loading

0 comments on commit 03dca9c

Please sign in to comment.