diff options
author | Piotr Jaszczyk <piotr.jaszczyk@nokia.com> | 2018-11-28 15:46:50 +0100 |
---|---|---|
committer | Piotr Jaszczyk <piotr.jaszczyk@nokia.com> | 2018-11-29 14:41:42 +0100 |
commit | dde383a2aa75f94c26d7949665b79cc95486a223 (patch) | |
tree | 75f3e8f564067afd0e67dbe6254183e45ca26944 /build | |
parent | 77f896523f2065b1da1be21545155a29edea5122 (diff) |
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 <piotr.jaszczyk@nokia.com>
Diffstat (limited to 'build')
10 files changed, 1111 insertions, 0 deletions
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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ ============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========================================================= + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <licenses> + <license> + <name>The Apache Software License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> + </license> + </licenses> + + <parent> + <groupId>org.onap.dcaegen2.collectors.hv-ves</groupId> + <artifactId>hv-collector-build</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + + <artifactId>hv-collector-analysis</artifactId> + <version>1.1.0-SNAPSHOT</version> + <description>VES HighVolume Collector :: Code analysis configuration</description> + + <dependencies> + <dependency> + <groupId>io.gitlab.arturbosch.detekt</groupId> + <artifactId>detekt-api</artifactId> + <version>${detekt.version}</version> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-stdlib-jdk8</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-reflect</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-compiler-embeddable</artifactId> + </dependency> + + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-script-runtime</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-script-util</artifactId> + </dependency> + + <dependency> + <groupId>io.gitlab.arturbosch.detekt</groupId> + <artifactId>detekt-test</artifactId> + <version>${detekt.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.jetbrains.spek</groupId> + <artifactId>spek-api</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.spek</groupId> + <artifactId>spek-junit-platform-engine</artifactId> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-test</artifactId> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + </dependency> + </dependencies> + + <build> + <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory> + <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <configuration> + <encoding>UTF-8</encoding> + </configuration> + </plugin> + + <plugin> + <artifactId>kotlin-maven-plugin</artifactId> + <groupId>org.jetbrains.kotlin</groupId> + <version>${kotlin.version}</version> + <configuration> + <jvmTarget>1.8</jvmTarget> + </configuration> + <executions> + <execution> + <id>compile</id> + <goals> + <goal>compile</goal> + </goals> + <configuration> + <sourceDirs> + <source>${project.build.sourceDirectory}</source> + </sourceDirs> + </configuration> + </execution> + <execution> + <id>test-compile</id> + <goals> + <goal>test-compile</goal> + </goals> + <configuration> + <sourceDirs> + <source>${project.build.testSourceDirectory}</source> + </sourceDirs> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> 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 <piotr.jaszczyk@nokia.com> + * @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<KtOperationExpression> { true } -> + "should not use any operators in logging expression" + args.anyDescendantOfType<KtCallExpression> { true } -> + "should not call anything in logging expression" + args.anyDescendantOfType<KtStringTemplateExpression> { 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 <piotr.jaszczyk@nokia.com> + * @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 <piotr.jaszczyk></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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ ============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========================================================= + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <licenses> + <license> + <name>The Apache Software License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> + </license> + </licenses> + + <parent> + <groupId>org.onap.dcaegen2.collectors.hv-ves</groupId> + <artifactId>hv-collector-build</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + + <artifactId>hv-collector-coverage</artifactId> + <description>VES HighVolume Collector :: Code coverage</description> + <packaging>pom</packaging> + + <properties> + <failIfMissingUnitTests>false</failIfMissingUnitTests> + <failIfMissingComponentTests>false</failIfMissingComponentTests> + </properties> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <executions> + <execution> + <id>jacoco-aggregate-report</id> + <phase>verify</phase> + <goals> + <goal>report-aggregate</goal> + </goals> + <configuration> + <excludes> + <!-- Exclude Protobuf-generated classes --> + <exclude>org/onap/ves/*</exclude> + </excludes> + <dataFileIncludes> + <dataFileInclude>**/jacoco-ut.exec</dataFileInclude> + <dataFileInclude>**/jacoco-it.exec</dataFileInclude> + </dataFileIncludes> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <executions> + <execution> + <id>check-coverage</id> + <phase>verify</phase> + <goals> + <goal>exec</goal> + </goals> + </execution> + </executions> + <configuration> + <skip>${skipTests}</skip> + <executable>${project.basedir}/check-coverage.sh</executable> + <workingDirectory>${project.basedir}</workingDirectory> + <arguments> + <argument>target/site/jacoco-aggregate/jacoco.xml</argument> + <argument>${jacoco.minimum.coverage}</argument> + </arguments> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-core</artifactId> + <version>${project.parent.version}</version> + </dependency> + <dependency> + <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-ct</artifactId> + <version>${project.parent.version}</version> + </dependency> + <dependency> + <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-dcae-app-simulator</artifactId> + <version>${project.parent.version}</version> + </dependency> + <dependency> + <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-domain</artifactId> + <version>${project.parent.version}</version> + </dependency> + <dependency> + <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-health-check</artifactId> + <version>${project.parent.version}</version> + </dependency> + <dependency> + <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-main</artifactId> + <version>${project.parent.version}</version> + </dependency> + <dependency> + <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-utils</artifactId> + <version>${project.parent.version}</version> + </dependency> + <dependency> + <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-ves-message-generator</artifactId> + <version>${project.parent.version}</version> + </dependency> + <dependency> + <groupId>${project.parent.groupId}</groupId> + <artifactId>hv-collector-xnf-simulator</artifactId> + <version>${project.parent.version}</version> + </dependency> + </dependencies> + +</project>
\ 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ ============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========================================================= + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <licenses> + <license> + <name>The Apache Software License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> + </license> + </licenses> + + <parent> + <groupId>org.onap.dcaegen2.collectors.hv-ves</groupId> + <artifactId>ves-hv-collector</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + + <artifactId>hv-collector-build</artifactId> + <version>1.1.0-SNAPSHOT</version> + <description>VES HighVolume Collector :: Build-time modules</description> + <packaging>pom</packaging> + + <modules> + <module>hv-collector-analysis</module> + <module>hv-collector-coverage</module> + </modules> +</project> |