From dde383a2aa75f94c26d7949665b79cc95486a223 Mon Sep 17 00:00:00 2001 From: Piotr Jaszczyk Date: Wed, 28 Nov 2018 15:46:50 +0100 Subject: Custom detekt rule for logger usage check Check if logger invocations don't use unoptimal invocations, eg. concatenation `debug("a=" + a)` instead of lambda use `debug {"a=" + a}` Unfortunately to avoid defining dependencies in many places and having circural dependencies it was necessarry to reorganize the maven module structure. The goal was to have `sources` module with production code and `build` module with build-time tooling (detekt rules among them). Issue-ID: DCAEGEN2-1002 Change-Id: I36e677b98972aaae6905d722597cbce5e863d201 Signed-off-by: Piotr Jaszczyk --- build/hv-collector-analysis/pom.xml | 150 +++++++ .../veshv/analysis/SuboptimalLoggerUsage.kt | 92 ++++ .../veshv/analysis/VesHvRuleSetProvider.kt | 36 ++ ...io.gitlab.arturbosch.detekt.api.RuleSetProvider | 1 + .../src/main/resources/onap-detekt-config.yml | 480 +++++++++++++++++++++ .../veshv/analysis/SuboptimalLoggerUsageTest.kt | 126 ++++++ .../services/javax.script.ScriptEngineFactory | 1 + build/hv-collector-coverage/check-coverage.sh | 30 ++ build/hv-collector-coverage/pom.xml | 147 +++++++ build/pom.xml | 48 +++ 10 files changed, 1111 insertions(+) create mode 100644 build/hv-collector-analysis/pom.xml create mode 100644 build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/SuboptimalLoggerUsage.kt create mode 100644 build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/VesHvRuleSetProvider.kt create mode 100644 build/hv-collector-analysis/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider create mode 100644 build/hv-collector-analysis/src/main/resources/onap-detekt-config.yml create mode 100644 build/hv-collector-analysis/src/test/kotlin/org/onap/dcae/collectors/veshv/analysis/SuboptimalLoggerUsageTest.kt create mode 100644 build/hv-collector-analysis/src/test/resources/META-INF/services/javax.script.ScriptEngineFactory create mode 100755 build/hv-collector-coverage/check-coverage.sh create mode 100644 build/hv-collector-coverage/pom.xml create mode 100644 build/pom.xml (limited to 'build') diff --git a/build/hv-collector-analysis/pom.xml b/build/hv-collector-analysis/pom.xml new file mode 100644 index 00000000..7a553b4e --- /dev/null +++ b/build/hv-collector-analysis/pom.xml @@ -0,0 +1,150 @@ + + + + 4.0.0 + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + org.onap.dcaegen2.collectors.hv-ves + hv-collector-build + 1.1.0-SNAPSHOT + .. + + + hv-collector-analysis + 1.1.0-SNAPSHOT + VES HighVolume Collector :: Code analysis configuration + + + + io.gitlab.arturbosch.detekt + detekt-api + ${detekt.version} + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + + + org.jetbrains.kotlin + kotlin-reflect + + + org.jetbrains.kotlin + kotlin-compiler-embeddable + + + + org.jetbrains.kotlin + kotlin-script-runtime + + + org.jetbrains.kotlin + kotlin-script-util + + + + io.gitlab.arturbosch.detekt + detekt-test + ${detekt.version} + test + + + org.jetbrains.spek + spek-api + + + org.jetbrains.spek + spek-junit-platform-engine + + + org.jetbrains.kotlin + kotlin-test + + + org.assertj + assertj-core + + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + + org.apache.maven.plugins + maven-resources-plugin + + UTF-8 + + + + + kotlin-maven-plugin + org.jetbrains.kotlin + ${kotlin.version} + + 1.8 + + + + compile + + compile + + + + ${project.build.sourceDirectory} + + + + + test-compile + + test-compile + + + + ${project.build.testSourceDirectory} + + + + + + + + diff --git a/build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/SuboptimalLoggerUsage.kt b/build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/SuboptimalLoggerUsage.kt new file mode 100644 index 00000000..a070584c --- /dev/null +++ b/build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/SuboptimalLoggerUsage.kt @@ -0,0 +1,92 @@ +/* + * ============LICENSE_START======================================================= + * dcaegen2-collectors-veshv + * ================================================================================ + * Copyright (C) 2018 NOKIA + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.collectors.veshv.analysis + +import io.gitlab.arturbosch.detekt.api.CodeSmell +import io.gitlab.arturbosch.detekt.api.Config +import io.gitlab.arturbosch.detekt.api.Debt +import io.gitlab.arturbosch.detekt.api.Entity +import io.gitlab.arturbosch.detekt.api.Issue +import io.gitlab.arturbosch.detekt.api.Rule +import io.gitlab.arturbosch.detekt.api.Severity +import org.jetbrains.kotlin.com.intellij.psi.PsiElement +import org.jetbrains.kotlin.psi.KtCallExpression +import org.jetbrains.kotlin.psi.KtOperationExpression +import org.jetbrains.kotlin.psi.KtStringTemplateExpression +import org.jetbrains.kotlin.psi.KtValueArgumentList +import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType + +/** + * @author Piotr Jaszczyk + * @since November 2018 + */ +class SuboptimalLoggerUsage(config: Config) : Rule(config) { + + override val issue = Issue(javaClass.simpleName, + Severity.Performance, + """ + Reports usage of unoptimized logger calls. + In Kotlin every method call (including logger calls) is eagerly evaluated by default. That means that + each argument will be evaluated even if loglevel is higher than in current call. The most common way of + mitigating this issue is to use lazy loading by means of lambda expressions, so instead of + log.debug("a=${'$'}a") we can write log.debug{ "a=${'$'}a" }. Logging string literals is fine - no + additional computation will be performed.""".trimIndent(), + Debt(mins = 10)) + + private val loggerNames = config.valueOrDefault("loggerNames", DEFAULT_LOGGER_NAMES).split(",") + + private val loggingMethods = config.valueOrDefault("loggingMethodNames", DEFAULT_LOGGING_METHOD_NAMES).split(",") + + override fun visitCallExpression(expression: KtCallExpression) { + val targetObject = expression.parent.firstChild + val methodName = expression.firstChild + + logExpressionArguments(targetObject, methodName) + ?.let(this::checkGettingWarningMessage) + ?.let { reportCodeSmell(expression, it) } + } + + private fun logExpressionArguments(targetObject: PsiElement, methodName: PsiElement) = + if (isLogExpression(targetObject, methodName)) + methodName.nextSibling as? KtValueArgumentList + else null + + private fun isLogExpression(targetObject: PsiElement, methodName: PsiElement) = + loggerNames.any(targetObject::textMatches) && loggingMethods.any(methodName::textMatches) + + private fun checkGettingWarningMessage(args: KtValueArgumentList) = when { + args.anyDescendantOfType { true } -> + "should not use any operators in logging expression" + args.anyDescendantOfType { true } -> + "should not call anything in logging expression" + args.anyDescendantOfType { it.hasInterpolation() } -> + "should not use string interpolation in logging expression" + else -> null + } + + private fun reportCodeSmell(expression: KtCallExpression, message: String) { + report(CodeSmell(issue, Entity.from(expression), message)) + } + + companion object { + const val DEFAULT_LOGGER_NAMES = "logger,LOGGER,log,LOG" + const val DEFAULT_LOGGING_METHOD_NAMES = "trace,debug,info,warn,error,severe" + } +} diff --git a/build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/VesHvRuleSetProvider.kt b/build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/VesHvRuleSetProvider.kt new file mode 100644 index 00000000..eec933dc --- /dev/null +++ b/build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/VesHvRuleSetProvider.kt @@ -0,0 +1,36 @@ +/* + * ============LICENSE_START======================================================= + * dcaegen2-collectors-veshv + * ================================================================================ + * Copyright (C) 2018 NOKIA + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.collectors.veshv.analysis + +import io.gitlab.arturbosch.detekt.api.Config +import io.gitlab.arturbosch.detekt.api.RuleSet +import io.gitlab.arturbosch.detekt.api.RuleSetProvider + +/** + * @author Piotr Jaszczyk + * @since November 2018 + */ +class VesHvRuleSetProvider : RuleSetProvider { + override val ruleSetId: String + get() = "HvVesCustomRules" + + override fun instance(config: Config) = RuleSet(ruleSetId, listOf(SuboptimalLoggerUsage(config))) + +} diff --git a/build/hv-collector-analysis/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider b/build/hv-collector-analysis/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider new file mode 100644 index 00000000..2b26f32f --- /dev/null +++ b/build/hv-collector-analysis/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider @@ -0,0 +1 @@ +org.onap.dcae.collectors.veshv.analysis.VesHvRuleSetProvider \ No newline at end of file diff --git a/build/hv-collector-analysis/src/main/resources/onap-detekt-config.yml b/build/hv-collector-analysis/src/main/resources/onap-detekt-config.yml new file mode 100644 index 00000000..f705d36c --- /dev/null +++ b/build/hv-collector-analysis/src/main/resources/onap-detekt-config.yml @@ -0,0 +1,480 @@ +autoCorrect: true +failFast: false + +test-pattern: # Configure exclusions for test sources + active: true + patterns: # Test file regexes + - '.*/test/.*' + - '.*Test.kt' + - '.*Spec.kt' + exclude-rule-sets: + - 'comments' + exclude-rules: + - 'NamingRules' + - 'WildcardImport' + - 'MagicNumber' + - 'MaxLineLength' + - 'LateinitUsage' + - 'StringLiteralDuplication' + - 'SpreadOperator' + - 'TooManyFunctions' + - 'ForEachOnRange' + +build: + maxIssues: 3 + weights: + # complexity: 2 + # LongParameterList: 1 + # style: 1 + # comments: 1 + +processors: + active: true + exclude: + # - 'FunctionCountProcessor' + # - 'PropertyCountProcessor' + # - 'ClassCountProcessor' + # - 'PackageCountProcessor' + # - 'KtFileCountProcessor' + +console-reports: + active: true + exclude: + # - 'ProjectStatisticsReport' + # - 'ComplexityReport' + # - 'NotificationReport' + # - 'FindingsReport' + # - 'BuildFailureReport' + +output-reports: + active: true + exclude: + # - 'HtmlOutputReport' + # - 'PlainOutputReport' + # - 'XmlOutputReport' + +comments: + active: true + CommentOverPrivateFunction: + active: false + CommentOverPrivateProperty: + active: false + EndOfSentenceFormat: + active: false + endOfSentenceFormat: ([.?!][ \t\n\r\f<])|([.?!]$) + UndocumentedPublicClass: + active: false + searchInNestedClass: true + searchInInnerClass: true + searchInInnerObject: true + searchInInnerInterface: true + UndocumentedPublicFunction: + active: false + +complexity: + active: true + ComplexCondition: + active: true + threshold: 4 + ComplexInterface: + active: false + threshold: 10 + includeStaticDeclarations: false + ComplexMethod: + active: true + threshold: 10 + ignoreSingleWhenExpression: false + LabeledExpression: + active: false + LargeClass: + active: true + threshold: 150 + LongMethod: + active: true + threshold: 20 + LongParameterList: + active: true + threshold: 6 + ignoreDefaultParameters: false + MethodOverloading: + active: false + threshold: 6 + NestedBlockDepth: + active: true + threshold: 4 + StringLiteralDuplication: + active: false + threshold: 3 + ignoreAnnotation: true + excludeStringsWithLessThan5Characters: true + ignoreStringsRegex: '$^' + TooManyFunctions: + active: true + thresholdInFiles: 11 + thresholdInClasses: 11 + thresholdInInterfaces: 11 + thresholdInObjects: 11 + thresholdInEnums: 11 + ignoreDeprecated: false + +empty-blocks: + active: true + EmptyCatchBlock: + active: true + allowedExceptionNameRegex: "^(_|(ignore|expected).*)" + EmptyClassBlock: + active: true + EmptyDefaultConstructor: + active: true + EmptyDoWhileBlock: + active: true + EmptyElseBlock: + active: true + EmptyFinallyBlock: + active: true + EmptyForBlock: + active: true + EmptyFunctionBlock: + active: true + ignoreOverriddenFunctions: false + EmptyIfBlock: + active: true + EmptyInitBlock: + active: true + EmptyKtFile: + active: true + EmptySecondaryConstructor: + active: true + EmptyWhenBlock: + active: true + EmptyWhileBlock: + active: true + +exceptions: + active: true + ExceptionRaisedInUnexpectedLocation: + active: false + methodNames: 'toString,hashCode,equals,finalize' + InstanceOfCheckForException: + active: false + NotImplementedDeclaration: + active: false + PrintStackTrace: + active: false + RethrowCaughtException: + active: false + ReturnFromFinally: + active: false + SwallowedException: + active: false + ThrowingExceptionFromFinally: + active: false + ThrowingExceptionInMain: + active: false + ThrowingExceptionsWithoutMessageOrCause: + active: false + exceptions: 'IllegalArgumentException,IllegalStateException,IOException' + ThrowingNewInstanceOfSameException: + active: false + TooGenericExceptionCaught: + active: true + exceptionNames: + - ArrayIndexOutOfBoundsException + - Error + - Exception + - IllegalMonitorStateException + - NullPointerException + - IndexOutOfBoundsException + - RuntimeException + - Throwable + TooGenericExceptionThrown: + active: true + exceptionNames: + - Error + - Exception + - Throwable + - RuntimeException + +formatting: + active: true + android: false + autoCorrect: true + ChainWrapping: + active: false + autoCorrect: true + CommentSpacing: + active: true + autoCorrect: true + Filename: + active: true + FinalNewline: + active: true + autoCorrect: true + ImportOrdering: + active: true + autoCorrect: true + Indentation: + active: true + autoCorrect: true + indentSize: 4 + continuationIndentSize: 4 + MaximumLineLength: + active: true + maxLineLength: 120 + ModifierOrdering: + active: true + autoCorrect: true + NoBlankLineBeforeRbrace: + active: true + autoCorrect: true + NoConsecutiveBlankLines: + active: true + autoCorrect: true + NoEmptyClassBody: + active: true + autoCorrect: true + NoItParamInMultilineLambda: + active: true + NoLineBreakAfterElse: + active: true + autoCorrect: true + NoLineBreakBeforeAssignment: + active: true + autoCorrect: true + NoMultipleSpaces: + active: true + autoCorrect: true + NoSemicolons: + active: true + autoCorrect: true + NoTrailingSpaces: + active: true + autoCorrect: true + NoUnitReturn: + active: true + autoCorrect: true + NoUnusedImports: + active: true + autoCorrect: true + NoWildcardImports: + active: true + autoCorrect: true + ParameterListWrapping: + active: false + autoCorrect: true + indentSize: 4 + SpacingAroundColon: + active: true + autoCorrect: true + SpacingAroundComma: + active: true + autoCorrect: true + SpacingAroundCurly: + active: true + autoCorrect: true + SpacingAroundKeyword: + active: true + autoCorrect: true + SpacingAroundOperators: + active: true + autoCorrect: true + SpacingAroundRangeOperator: + active: true + autoCorrect: true + StringTemplate: + active: true + autoCorrect: true + +naming: + active: true + ClassNaming: + active: true + classPattern: '[A-Z$][a-zA-Z0-9$]*' + EnumNaming: + active: true + enumEntryPattern: '^[A-Z][_a-zA-Z0-9]*' + ForbiddenClassName: + active: false + forbiddenName: '' + FunctionMaxLength: + active: false + maximumFunctionNameLength: 30 + FunctionMinLength: + active: false + minimumFunctionNameLength: 3 + FunctionNaming: + active: true + functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$' + excludeClassPattern: '$^' + MatchingDeclarationName: + active: false + MemberNameEqualsClassName: + active: false + ignoreOverriddenFunction: true + ObjectPropertyNaming: + active: true + propertyPattern: '[A-Za-z][_A-Za-z0-9]*' + constantPattern: '[A-Za-z][_A-Za-z0-9]*' + PackageNaming: + active: true + packagePattern: '^[a-z]+(\.[a-z][a-z0-9]*)*$' + TopLevelPropertyNaming: + active: true + constantPattern: '[A-Z][_A-Z0-9]*' + propertyPattern: '[A-Za-z][_A-Za-z0-9]*' + privatePropertyPattern: '(_)?[A-Za-z][A-Za-z0-9]*' + VariableMaxLength: + active: false + maximumVariableNameLength: 64 + VariableMinLength: + active: false + minimumVariableNameLength: 1 + VariableNaming: + active: true + variablePattern: '[a-z][A-Za-z0-9]*' + privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + +performance: + active: true + ForEachOnRange: + active: true + SpreadOperator: + active: true + UnnecessaryTemporaryInstantiation: + active: true + +potential-bugs: + active: true + DuplicateCaseInWhenExpression: + active: true + EqualsAlwaysReturnsTrueOrFalse: + active: false + EqualsWithHashCodeExist: + active: true + ExplicitGarbageCollectionCall: + active: true + InvalidRange: + active: false + IteratorHasNextCallsNextMethod: + active: false + IteratorNotThrowingNoSuchElementException: + active: false + LateinitUsage: + active: false + excludeAnnotatedProperties: "" + ignoreOnClassesPattern: "" + UnconditionalJumpStatementInLoop: + active: false + UnreachableCode: + active: true + UnsafeCallOnNullableType: + active: false + UnsafeCast: + active: false + UselessPostfixExpression: + active: false + WrongEqualsTypeParameter: + active: false + +style: + active: true + CollapsibleIfStatements: + active: false + DataClassContainsFunctions: + active: false + conversionFunctionPrefix: 'to' + EqualsNullCall: + active: false + ExpressionBodySyntax: + active: false + ForbiddenComment: + active: true + values: 'TODO:,FIXME:,STOPSHIP:' + ForbiddenImport: + active: false + imports: '' + FunctionOnlyReturningConstant: + active: false + ignoreOverridableFunction: true + excludedFunctions: 'describeContents' + LoopWithTooManyJumpStatements: + active: false + maxJumpCount: 1 + MagicNumber: + active: true + ignoreNumbers: '-1,0,1,2' + ignoreHashCodeFunction: false + ignorePropertyDeclaration: false + ignoreConstantDeclaration: true + ignoreCompanionObjectPropertyDeclaration: true + ignoreAnnotation: false + ignoreNamedArgument: true + ignoreEnums: false + MaxLineLength: + active: true + maxLineLength: 120 + excludePackageStatements: false + excludeImportStatements: false + excludeCommentStatements: false + MayBeConst: + active: false + ModifierOrder: + active: true + NestedClassesVisibility: + active: false + NewLineAtEndOfFile: + active: true + NoTabs: + active: false + OptionalAbstractKeyword: + active: true + OptionalUnit: + active: false + OptionalWhenBraces: + active: false + ProtectedMemberInFinalClass: + active: false + RedundantVisibilityModifierRule: + active: false + ReturnCount: + active: true + max: 2 + excludedFunctions: "equals" + SafeCast: + active: true + SerialVersionUIDInSerializableClass: + active: false + SpacingBetweenPackageAndImports: + active: false + ThrowsCount: + active: true + max: 2 + TrailingWhitespace: + active: false + UnnecessaryAbstractClass: + active: false + UnnecessaryInheritance: + active: false + UnnecessaryParentheses: + active: false + UntilInsteadOfRangeTo: + active: false + UnusedImports: + active: false + UnusedPrivateMember: + active: true + allowedNames: "(_.*|ignored|expected)" + UseDataClass: + active: false + excludeAnnotatedClasses: "" + UtilityClassWithPublicConstructor: + active: false + WildcardImport: + active: true + excludeImports: 'java.util.*,kotlinx.android.synthetic.*' + +HvVesCustomRules: + active: true + SuboptimalLoggerUsage: + active: true diff --git a/build/hv-collector-analysis/src/test/kotlin/org/onap/dcae/collectors/veshv/analysis/SuboptimalLoggerUsageTest.kt b/build/hv-collector-analysis/src/test/kotlin/org/onap/dcae/collectors/veshv/analysis/SuboptimalLoggerUsageTest.kt new file mode 100644 index 00000000..0a1d658b --- /dev/null +++ b/build/hv-collector-analysis/src/test/kotlin/org/onap/dcae/collectors/veshv/analysis/SuboptimalLoggerUsageTest.kt @@ -0,0 +1,126 @@ +/* + * ============LICENSE_START======================================================= + * dcaegen2-collectors-veshv + * ================================================================================ + * Copyright (C) 2018 NOKIA + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.collectors.veshv.analysis + +import io.gitlab.arturbosch.detekt.api.Config +import io.gitlab.arturbosch.detekt.test.TestConfig +import io.gitlab.arturbosch.detekt.test.assertThat +import io.gitlab.arturbosch.detekt.test.compileAndLint +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.dsl.describe +import org.jetbrains.spek.api.dsl.it +import org.jetbrains.spek.api.dsl.xdescribe + +/** + * @author Piotr Jaszczyk @nokia.com> + * @since November 2018 + */ +internal class SuboptimalLoggerUsageTest : Spek({ + + fun checkPassingCase(code: String, cut: SuboptimalLoggerUsage = SuboptimalLoggerUsage(Config.empty)) { + describe(code) { + val findings = cut.compileAndLint(CodeSamples.code(code)) + + it("should pass") { + assertThat(findings).isEmpty() + } + } + } + + fun checkFailingCase(code: String, cut: SuboptimalLoggerUsage = SuboptimalLoggerUsage(Config.empty)) { + describe(code) { + val findings = cut.compileAndLint(CodeSamples.code(code)) + + it("should fail") { + assertThat(findings).isNotEmpty() + } + } + } + + describe("passing cases") { + checkPassingCase(CodeSamples.noConcatCall) + checkPassingCase(CodeSamples.exceptionCall) + checkPassingCase(CodeSamples.lambdaCall) + checkPassingCase(CodeSamples.lambdaFunctionCall) + checkPassingCase(CodeSamples.lambdaExceptionCall) + } + + + describe("failing cases") { + checkFailingCase(CodeSamples.plainConcatCall) + checkFailingCase(CodeSamples.expansionCall) + checkFailingCase(CodeSamples.plainConcatExceptionCall) + checkFailingCase(CodeSamples.expansionExceptionCall) + } + + describe("custom configuration") { + val cut = SuboptimalLoggerUsage(TestConfig(mapOf("loggerNames" to "l,lo", "loggingMethodNames" to "print"))) + val strangeLogger = """ + val l = object { + fun print(m: String) { } + } + val lo = l + """.trimIndent() + + checkPassingCase(CodeSamples.plainConcatCall, cut) + + checkPassingCase(""" + $strangeLogger + l.print("n")""".trimIndent(), cut) + + checkFailingCase(""" + $strangeLogger + l.print("n=" + n)""".trimIndent(), cut) + + checkFailingCase(""" + $strangeLogger + lo.print("n=${'$'}n")""".trimIndent(), cut) + } +}) + +object CodeSamples { + private val codeBefore = """ + object logger { + fun debug(msg: String) { println(msg) } + fun debug(msg: String, ex: Throwable) { println(msg + ". Cause: " + ex) } + fun debug(msg: () -> String) { println(msg()) } + fun debug(ex: Throwable, msg: () -> String) { println(msg() + ". Cause: " + ex) } + } + + fun execute(n: Integer) { + val ex = Exception() + + """.trimIndent() + private const val codeAfter = """}""" + + const val noConcatCall = """logger.debug("Executing...")""" + const val exceptionCall = """logger.debug("Fail", ex)""" + const val lambdaCall = """logger.debug{ "n=${'$'}n" }""" + const val lambdaFunctionCall = """logger.debug { n.toString() }""" + const val lambdaExceptionCall = """logger.debug(ex) { "epic fail on n=" + n }""" + + const val plainConcatCall = """logger.debug("n=" + n)""" + const val expansionCall = """logger.debug("n=${'$'}n")""" + const val plainConcatExceptionCall = """logger.debug("Fail. n=" + n, ex)""" + const val expansionExceptionCall = """logger.debug("Fail. n=${'$'}n", ex)""" + + + fun code(core: String) = codeBefore + core + codeAfter +} \ No newline at end of file diff --git a/build/hv-collector-analysis/src/test/resources/META-INF/services/javax.script.ScriptEngineFactory b/build/hv-collector-analysis/src/test/resources/META-INF/services/javax.script.ScriptEngineFactory new file mode 100644 index 00000000..f8f59003 --- /dev/null +++ b/build/hv-collector-analysis/src/test/resources/META-INF/services/javax.script.ScriptEngineFactory @@ -0,0 +1 @@ +org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory \ No newline at end of file diff --git a/build/hv-collector-coverage/check-coverage.sh b/build/hv-collector-coverage/check-coverage.sh new file mode 100755 index 00000000..956891ac --- /dev/null +++ b/build/hv-collector-coverage/check-coverage.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail + +JACOCO_REPORT="$1" +MIN_COVERAGE_PERCENT="$2" +LOG_FILE=target/check-coverage.log + +function coverage_from_report() { + local xpath_expr="string(/report/counter[@type='INSTRUCTION']/@$1)" + xpath -q -e "$xpath_expr" "$JACOCO_REPORT" 2>> ${LOG_FILE} +} + +missed=$(coverage_from_report missed) +covered=$(coverage_from_report covered) +total=$(($missed + $covered)) +coverage=$((100 * $covered / $total)) + +if [[ $(wc -c < ${LOG_FILE}) > 0 ]]; then + echo "Warnings from xpath evaluation:" + cat ${LOG_FILE} + echo +fi + +echo "Coverage: $coverage% (covered/total: $covered/$total)" + +if [[ ${coverage} -lt ${MIN_COVERAGE_PERCENT} ]]; then + echo "Coverage is too low. Minimum coverage: $MIN_COVERAGE_PERCENT%" + exit 1 +fi + diff --git a/build/hv-collector-coverage/pom.xml b/build/hv-collector-coverage/pom.xml new file mode 100644 index 00000000..9b3f257a --- /dev/null +++ b/build/hv-collector-coverage/pom.xml @@ -0,0 +1,147 @@ + + + + 4.0.0 + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + org.onap.dcaegen2.collectors.hv-ves + hv-collector-build + 1.1.0-SNAPSHOT + .. + + + hv-collector-coverage + VES HighVolume Collector :: Code coverage + pom + + + false + false + + + + + + org.jacoco + jacoco-maven-plugin + + + jacoco-aggregate-report + verify + + report-aggregate + + + + + org/onap/ves/* + + + **/jacoco-ut.exec + **/jacoco-it.exec + + + + + + + org.codehaus.mojo + exec-maven-plugin + + + check-coverage + verify + + exec + + + + + ${skipTests} + ${project.basedir}/check-coverage.sh + ${project.basedir} + + target/site/jacoco-aggregate/jacoco.xml + ${jacoco.minimum.coverage} + + + + + + + + + ${project.parent.groupId} + hv-collector-core + ${project.parent.version} + + + ${project.parent.groupId} + hv-collector-ct + ${project.parent.version} + + + ${project.parent.groupId} + hv-collector-dcae-app-simulator + ${project.parent.version} + + + ${project.parent.groupId} + hv-collector-domain + ${project.parent.version} + + + ${project.parent.groupId} + hv-collector-health-check + ${project.parent.version} + + + ${project.parent.groupId} + hv-collector-main + ${project.parent.version} + + + ${project.parent.groupId} + hv-collector-utils + ${project.parent.version} + + + ${project.parent.groupId} + hv-collector-ves-message-generator + ${project.parent.version} + + + ${project.parent.groupId} + hv-collector-xnf-simulator + ${project.parent.version} + + + + \ No newline at end of file diff --git a/build/pom.xml b/build/pom.xml new file mode 100644 index 00000000..fb1b8fb3 --- /dev/null +++ b/build/pom.xml @@ -0,0 +1,48 @@ + + + + + 4.0.0 + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + org.onap.dcaegen2.collectors.hv-ves + ves-hv-collector + 1.1.0-SNAPSHOT + .. + + + hv-collector-build + 1.1.0-SNAPSHOT + VES HighVolume Collector :: Build-time modules + pom + + + hv-collector-analysis + hv-collector-coverage + + -- cgit 1.2.3-korg