Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Build Status](https://github.com/exasol/import-export-udf-common-scala/actions/workflows/ci-build.yml/badge.svg)](https://github.com/exasol/import-export-udf-common-scala/actions/workflows/ci-build.yml)
[![Coveralls](https://img.shields.io/coveralls/exasol/import-export-udf-common-scala.svg)](https://coveralls.io/github/exasol/import-export-udf-common-scala)
[![Maven Central](https://img.shields.io/maven-central/v/com.exasol/import-export-udf-common-scala)](https://search.maven.org/artifact/com.exasol/import-export-udf-common-scala)
[![Maven Central](https://img.shields.io/maven-central/v/com.exasol/import-export-udf-common-scala)](https://search.maven.org/artifact/com.exasol/import-export-udf-common-scala_2.13)

[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=com.exasol%3Aimport-export-udf-common-scala&metric=alert_status)](https://sonarcloud.io/dashboard?id=com.exasol%3Aimport-export-udf-common-scala)

Expand Down
7 changes: 4 additions & 3 deletions doc/changes/changes_0.3.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ In this release, we added custom user defined property separators. We also migra

* #15: Migrated to Github actions
* #18: Added unified error codes
* #20: Added file location checker

## Dependency Updates

Expand All @@ -28,17 +29,17 @@ In this release, we added custom user defined property separators. We also migra

### Test Dependency Updates

* Updated `org.mockito:mockito-core:test:3.6.0` to `3.12.4`
* Updated `org.mockito:mockito-core:test:3.6.0` to `4.0.0`
* Updated `org.scalatest:scalatest:test:3.2.2` to `3.2.10`

### Plugin Updates

* Added `org.scalameta:sbt-scalafmt:2.4.3`
* Updated `com.jsuereth:sbt-pgp:2.0.1` to `2.1.1`
* Updated `com.timushev.sbt:sbt-updates:0.5.1` to `0.6.0`
* Updated `com.typesafe.sbt:sbt-git:1.0.0` to `1.0.1`
* Updated `com.typesafe.sbt:sbt-git:1.0.0` to `1.0.2`
* Updated `org.scoverage:sbt-coveralls:1.2.7` to `1.3.1`
* Updated `org.scoverage:sbt-scoverage:1.6.1` to `1.9.0`
* Updated `org.scoverage:sbt-scoverage:1.6.1` to `1.9.1`
* Updated `org.wartremover:sbt-wartremover:2.4.12` to `2.4.16`
* Updated `org.wartremover:sbt-wartremover-contib:1.3.10` to `1.3.12`
* Updated `org.xerial.sbt:sbt-sonatype:3.9.4` to `3.9.10`
Expand Down
2 changes: 1 addition & 1 deletion project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ object Dependencies {
// Test dependencies versions
private val ScalaTestVersion = "3.2.10"
private val ScalaTestPlusVersion = "1.0.0-M2"
private val MockitoCoreVersion = "3.12.4"
private val MockitoCoreVersion = "4.0.0"

val ExasolResolvers: Seq[Resolver] = Seq(
"Exasol Releases" at "https://maven.exasol.com/artifactory/exasol-releases"
Expand Down
4 changes: 2 additions & 2 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ addSbtPlugin("com.thoughtworks.sbt-api-mappings" % "sbt-api-mappings" % "3.0.0")

// Adds Scala Code Coverage (Scoverage) used during unit tests
// http://github.com/scoverage/sbt-scoverage
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.0")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.1")

// Adds SBT Coveralls plugin for uploading Scala code coverage to
// https://coveralls.io
Expand Down Expand Up @@ -46,4 +46,4 @@ addSbtPlugin("com.jsuereth" % "sbt-pgp" % "2.1.1")

// Adds a `git` plugin
// https://github.com/sbt/sbt-git
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.1")
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.2")
2 changes: 1 addition & 1 deletion scripts/ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ set -o errtrace -o nounset -o pipefail -o errexit
BASE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
cd "$BASE_DIR"

DEFAULT_SCALA_VERSION=2.12.12
DEFAULT_SCALA_VERSION=2.13.6

if [[ -z "${SCALA_VERSION:-}" ]]; then
echo "Environment variable SCALA_VERSION is not set"
Expand Down
10 changes: 10 additions & 0 deletions src/main/scala/com/exasol/common/file/BucketFSFileChecker.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.exasol.common.file

/**
* A BucketFS file location checker implementation.
*/
class BucketFSFileChecker extends FileChecker {

override final def getLocationPrefix(): String = "/buckets"

}
59 changes: 59 additions & 0 deletions src/main/scala/com/exasol/common/file/FileChecker.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.exasol.common.file

import java.io.File
import java.io.IOException
import java.io.UncheckedIOException
import java.nio.file.Files
import java.nio.file.Paths

import com.exasol.errorreporting.ExaError

/**
* An abstract class for file checker implementations.
*/
abstract class FileChecker {

/**
* Returns an expected prefix that file paths starts with for this filesystem.
*
* @return a location prefix
*/
def getLocationPrefix(): String

/**
* Cheks if path is regular file.
*
* @param path a path to file location
* @return {@code true} if regular file, otherwise {@code false}
*/
final def isRegularFile(filePath: String): Boolean = {
val path = Paths.get(filePath)
checkStartsWithPath(path.toFile())
Files.isRegularFile(path)
}

protected[file] final def checkStartsWithPath(file: File): Unit =
try {
val absolutePath = file.getCanonicalPath()
if (!absolutePath.startsWith(getLocationPrefix())) {
throw new IllegalArgumentException(
ExaError
.messageBuilder("E-IEUCS-12")
.message("Provided path {{PATH}} does not start with expected location prefix.", absolutePath)
.mitigation("Please make sure that file path start with {{PREFIX}}.", getLocationPrefix())
.toString()
)
}
} catch {
case exception: IOException =>
throw new UncheckedIOException(
ExaError
.messageBuilder("E-IEUCS-13")
.message("Failed to open path {{PATH}}.", file.getAbsolutePath())
.mitigation("Please make sure that file exists and starts with location {{PREFIX}}", getLocationPrefix())
.toString(),
exception
)
}

}
52 changes: 52 additions & 0 deletions src/test/scala/com/exasol/common/file/FileCheckerTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.exasol.common.file

import java.io.File
import java.io.IOException
import java.io.UncheckedIOException
import java.nio.file.Files

import org.mockito.Mockito.when
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
import org.scalatestplus.mockito.MockitoSugar

class FileCheckerTest extends AnyFunSuite with Matchers with MockitoSugar {

test("temporary file checker checks correct path") {
val fileParent = "/tmp/bfsdefault/bucket1"
val file = new File(fileParent, "/file.txt")
Files.createDirectories(new File(fileParent).toPath())
Files.createFile(file.toPath())
assert(new TemporaryFileChecker().isRegularFile("/tmp/bfsdefault/bucket1/file.txt") === true)
file.delete()
}

test("bucketfs file checker throws when path is missing") {
assert(new BucketFSFileChecker().isRegularFile("/buckets/non-existing/default/file.txt") === false)
}

test("bucketfs file checker throws when path does not start with expected prefix") {
val thrown = intercept[IllegalArgumentException] {
new BucketFSFileChecker().isRegularFile("/var/log/bucket1/file.txt")
}
val message = thrown.getMessage()
assert(message.startsWith("E-IEUCS-12"))
assert(message.contains("Provided path '/var/log/bucket1/file.txt' does not start with expected"))
assert(message.contains("Please make sure that file path start with '/buckets'."))
}

test("bucketfs file checker throws ioexception") {
val file = mock[File]
when(file.getAbsolutePath()).thenReturn("test/path")
when(file.getCanonicalPath()).thenThrow(new IOException())
val thrown = intercept[UncheckedIOException] {
new BucketFSFileChecker().checkStartsWithPath(file)
}
assert(thrown.getMessage().startsWith("E-IEUCS-13: Failed to open path 'test/path'."))
}

class TemporaryFileChecker extends FileChecker {
override final def getLocationPrefix(): String = "/tmp"
}

}