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
6 changes: 6 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ maven.install(
"org.apache.commons:commons-pool2:2.11.1",
"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2",
"org.mockito.kotlin:mockito-kotlin:5.4.0",
# SLF4J binding for JGit (serve command). JGit depends on slf4j-api but ships no binding, so
# without one SLF4J prints a "Failed to load class StaticLoggerBinder / Defaulting to NOP"
# warning to stderr on first use. slf4j-nop supplies the binding (silencing the warning) and
# discards JGit's internal logs, keeping the CLI's stderr clean. Version tracks the slf4j-api
# that JGit 5.13.x resolves (1.7.30).
"org.slf4j:slf4j-nop:1.7.30",
],
fail_if_repin_required = True,
lock_file = "//:maven_install.json",
Expand Down
14 changes: 14 additions & 0 deletions cli/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ kt_jvm_library(
"@bazel_diff_maven//:org_eclipse_jgit_org_eclipse_jgit",
"@bazel_diff_maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm",
],
# SLF4J binding for JGit. Not referenced by bazel-diff code (JGit uses it internally), so it is a
# pure runtime dep: it supplies org.slf4j.impl.StaticLoggerBinder, silencing the "Defaulting to
# NOP logger" warning SLF4J prints to stderr when no binding is on the classpath.
runtime_deps = [
"@bazel_diff_maven//:org_slf4j_slf4j_nop",
],
)

kt_jvm_test(
Expand Down Expand Up @@ -169,6 +175,12 @@ kt_jvm_test(
runtime_deps = [":cli-test-lib"],
)

kt_jvm_test(
name = "Slf4jBindingTest",
test_class = "com.bazel_diff.log.Slf4jBindingTest",
runtime_deps = [":cli-test-lib"],
)

kt_jvm_test(
name = "BazelModServiceTest",
test_class = "com.bazel_diff.bazel.BazelModServiceTest",
Expand Down Expand Up @@ -273,6 +285,8 @@ kt_jvm_library(
"@bazel_diff_maven//:io_insert_koin_koin_test_jvm",
"@bazel_diff_maven//:junit_junit",
"@bazel_diff_maven//:org_mockito_kotlin_mockito_kotlin",
# Compile-time API for Slf4jBindingTest; the runtime binding (slf4j-nop) comes via cli-lib.
"@bazel_diff_maven//:org_slf4j_slf4j_api",
],
)

Expand Down
61 changes: 61 additions & 0 deletions cli/src/test/kotlin/com/bazel_diff/log/Slf4jBindingTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.bazel_diff.log

import assertk.assertThat
import assertk.assertions.doesNotContain
import assertk.assertions.isNotNull
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.slf4j.LoggerFactory

/**
* Regression test for the SLF4J warning printed by `bazel-diff serve`:
* ```
* SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
* SLF4J: Defaulting to no-operation (NOP) logger implementation
* ```
*
* JGit (the serve command's in-process git engine) depends on `slf4j-api` but ships no binding. With
* no `org.slf4j.impl.StaticLoggerBinder` on the classpath, SLF4J falls back to a NOP logger and
* prints the warning above to stderr on first use. Shipping `slf4j-nop` as a runtime dep supplies the
* binding, silencing the warning while discarding JGit's internal logs (keeping the CLI stderr clean).
*/
class Slf4jBindingTest {
private val originalErr = System.err
private lateinit var captured: ByteArrayOutputStream

@Before
fun setUp() {
captured = ByteArrayOutputStream()
System.setErr(PrintStream(captured))
}

@After
fun tearDown() {
System.setErr(originalErr)
}

@Test
fun staticLoggerBinderIsOnTheClasspath() {
// This is the exact class SLF4J fails to load when no binding is present ("Failed to load class
// org.slf4j.impl.StaticLoggerBinder"). If it resolves, the NOP-fallback warning cannot be
// printed — a deterministic guard that survives SLF4J's once-per-JVM static init ordering.
val binder = Class.forName("org.slf4j.impl.StaticLoggerBinder")
assertThat(binder).isNotNull()
}

@Test
fun obtainingAndUsingALoggerDoesNotPrintNopFallbackWarning() {
// Exercises the same path JGit takes: resolve a logger and emit a record. With a binding present
// this is silent; without one, SLF4J's static init prints the warning to stderr.
val logger = LoggerFactory.getLogger(Slf4jBindingTest::class.java)
assertThat(logger).isNotNull()
logger.info("bazel-diff slf4j binding smoke test")

val err = captured.toString()
assertThat(err).doesNotContain("StaticLoggerBinder")
assertThat(err).doesNotContain("NOP logger")
}
}
19 changes: 17 additions & 2 deletions maven_install.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"org.eclipse.jgit:org.eclipse.jgit": -1935467463,
"org.jetbrains.kotlinx:kotlinx-coroutines-core": -542524036,
"org.mockito.kotlin:mockito-kotlin": 1836434344,
"org.slf4j:slf4j-nop": 1480452039,
"repositories": -1949687017
},
"__RESOLVED_ARTIFACTS_HASH": {
Expand Down Expand Up @@ -52,7 +53,8 @@
"org.mockito:mockito-core": -960687581,
"org.objenesis:objenesis": 1798216877,
"org.opentest4j:opentest4j": -1584531193,
"org.slf4j:slf4j-api": -801231047
"org.slf4j:slf4j-api": -801231047,
"org.slf4j:slf4j-nop": -2006403554
},
"conflict_resolution": {
"io.insert-koin:koin-core-jvm:3.1.6": "io.insert-koin:koin-core-jvm:4.0.0"
Expand Down Expand Up @@ -285,6 +287,12 @@
"jar": "cdba07964d1bb40a0761485c6b1e8c2f8fd9eb1d19c53928ac0d7f9510105c57"
},
"version": "1.7.30"
},
"org.slf4j:slf4j-nop": {
"shasums": {
"jar": "2d550dcefaea23d223b72027dbc7cbdb7327676ccefdd9cfe49cf9ea8e9ac8e0"
},
"version": "1.7.30"
}
},
"dependencies": {
Expand Down Expand Up @@ -371,6 +379,9 @@
"net.bytebuddy:byte-buddy",
"net.bytebuddy:byte-buddy-agent",
"org.objenesis:objenesis"
],
"org.slf4j:slf4j-nop": [
"org.slf4j:slf4j-api"
]
},
"packages": {
Expand Down Expand Up @@ -887,6 +898,9 @@
"org.slf4j.event",
"org.slf4j.helpers",
"org.slf4j.spi"
],
"org.slf4j:slf4j-nop": [
"org.slf4j.impl"
]
},
"repositories": {
Expand Down Expand Up @@ -928,7 +942,8 @@
"org.mockito:mockito-core",
"org.objenesis:objenesis",
"org.opentest4j:opentest4j",
"org.slf4j:slf4j-api"
"org.slf4j:slf4j-api",
"org.slf4j:slf4j-nop"
]
},
"services": {
Expand Down
Loading