diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 75d6dbb2..36a73f20 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -22,32 +22,6 @@ steps: run: java-common command: './gradlew check test' - - label: ':docker: Mazerunner java8 tests batch 1' - key: 'java-mazerunner-tests-1' - depends_on: 'java-jvm-build' - timeout_in_minutes: 30 - plugins: - - docker-compose#v3.7.0: - run: java8-mazerunner - - artifacts#v1.9.0: - download: "maven-repository.zip" - command: - - 'features/scripts/assemble-fixtures.sh' - - 'bundle exec maze-runner --exclude=features/[^a-m].*.feature' - - - label: ':docker: Mazerunner java8 tests batch 2' - key: 'java-mazerunner-tests-2' - depends_on: 'java-jvm-build' - timeout_in_minutes: 30 - plugins: - - docker-compose#v3.7.0: - run: java8-mazerunner - - artifacts#v1.9.0: - download: "maven-repository.zip" - command: - - 'features/scripts/assemble-fixtures.sh' - - 'bundle exec maze-runner --exclude=features/[^n-z].*.feature' - - label: ':docker: Mazerunner java17 tests batch 1' key: 'java-mazerunner-tests-3' depends_on: 'java-jvm-build' @@ -57,6 +31,7 @@ steps: run: java17-mazerunner - artifacts#v1.9.0: download: "maven-repository.zip" + upload: "maze_output/maze_output.zip" command: - 'features/scripts/assemble-fixtures.sh' - 'bundle exec maze-runner --exclude=features/[^a-m].*.feature' @@ -70,6 +45,7 @@ steps: run: java17-mazerunner - artifacts#v1.9.0: download: "maven-repository.zip" + upload: "maze_output/maze_output.zip" command: - 'features/scripts/assemble-fixtures.sh' - 'bundle exec maze-runner --exclude=features/[^n-z].*.feature' diff --git a/Gemfile b/Gemfile index 85813553..1dcbd4b1 100644 --- a/Gemfile +++ b/Gemfile @@ -2,3 +2,5 @@ source 'https://rubygems.org' gem 'bugsnag-maze-runner', '~>9.0' gem 'os' +# Pin power_assert to avoid compatibility issues with test-unit +gem 'power_assert', '< 3.0.0' diff --git a/bugsnag-spring/build.gradle b/bugsnag-spring/build.gradle deleted file mode 100644 index 379cc762..00000000 --- a/bugsnag-spring/build.gradle +++ /dev/null @@ -1,204 +0,0 @@ -ext { - jakartaSpringVersion = '6.0.0' - jakartaSpringBootVersion = '3.0.0' - - javaxSpringVersion = '5.3.20' - javaxSpringBootVersion = '2.5.14' -} - -apply plugin: 'java-library' - -repositories { - mavenCentral() -} - -java { - withJavadocJar() - toolchain { - languageVersion.set(JavaLanguageVersion.of(8)) - } -} - -// We use 3 custom configurations and matching sourceSets to avoid the standard behaviours which interfere with -// our compilation structure -configurations { - compileCommon - compileJavax - compileJakarta -} - -sourceSets { - common { - java - // common.compileClasspath includes the compileJavax classpath in order to give the common classes access - // to Spring without confusing the dependencies, including it here ensures that any use of javax.* packages - // in src/common will result in test failures (although not compile failures) - // we need the javax.* packages included here so that the compiler can type-check all the way up the hierarchy - // for things like "ServletRequestBindingException extends ServletException" - compileClasspath += configurations.compileCommon + configurations.compileJavax - } - javax { - java - compileClasspath += configurations.compileJavax + common.output + configurations.compileCommon - } - jakarta { - java - compileClasspath += configurations.compileJakarta + common.output + configurations.compileCommon - } -} - -// test sourceSets -sourceSets { - commonTest { - java - } - javaxTest { - java - compileClasspath += javax.output + javax.compileClasspath + commonTest.output + commonTest.runtimeClasspath + common.output - runtimeClasspath = compileClasspath - } - jakartaTest { - java - compileClasspath += jakarta.output + jakarta.compileClasspath + commonTest.output + commonTest.runtimeClasspath + common.output - runtimeClasspath = compileClasspath - } -} - -tasks.register('sourceJar', Jar).configure { - from( - sourceSets.common.allJava, - sourceSets.javax.allJava, - sourceSets.jakarta.allJava - ) -} - -// do not move this higher - sourceJar must be registered before we apply common.gradle -apply from: '../common.gradle' - -compileJava.dependsOn(compileCommonJava, compileJavaxJava, compileJakartaJava) - -// Separated Javax / Jakarta tests ------------------------------------------------------------------------------------- - -compileJakartaJava { - // set the compiler for the `jakarta` sourceSet to Java17 - javaCompiler.set( - javaToolchains.compilerFor { - languageVersion = JavaLanguageVersion.of(17) - } - ) -} - -compileJakartaTestJava { - // set the compiler for the `jakartaTest` sourceSet to Java17 - javaCompiler.set( - javaToolchains.compilerFor { - languageVersion = JavaLanguageVersion.of(17) - } - ) -} - -testClasses.dependsOn(javaxTestClasses, jakartaTestClasses) - -tasks.register('testJakarta', Test) { - testClassesDirs = sourceSets.jakartaTest.output.classesDirs - classpath = sourceSets.jakartaTest.output.classesDirs + sourceSets.jakartaTest.runtimeClasspath - javaLauncher.set( - javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(17) - } - ) - - dependsOn(jakartaTestClasses) -} - -tasks.register('testJavax', Test) { - testClassesDirs = sourceSets.javaxTest.output.classesDirs - classpath = sourceSets.javaxTest.output.classesDirs + sourceSets.javaxTest.runtimeClasspath - javaLauncher.set( - javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(8) - } - ) - - dependsOn(javaxTestClasses) -} - -test.dependsOn(testJakarta, testJavax) - -dependencies { - compileCommon project(':bugsnag') - - compileCommon "ch.qos.logback:logback-core:${logbackVersion}" - compileCommon "org.slf4j:slf4j-api:${slf4jApiVersion}" - - compileJavax "javax.servlet:javax.servlet-api:${javaxServletApiVersion}" - compileJavax "org.springframework:spring-webmvc:${javaxSpringVersion}" - compileJavax "org.springframework.boot:spring-boot:${javaxSpringBootVersion}" - compileJavax "org.springframework:spring-aop:${javaxSpringVersion}" - - compileJakarta "jakarta.servlet:jakarta.servlet-api:${jakartaServletApiVersion}" - compileJakarta "org.springframework:spring-webmvc:${jakartaSpringVersion}" - compileJakarta "org.springframework.boot:spring-boot:${jakartaSpringBootVersion}" - compileJakarta "org.springframework:spring-aop:${jakartaSpringVersion}" - - - commonTestImplementation project(':bugsnag').sourceSets.test.output - commonTestImplementation project(':bugsnag') - - commonTestImplementation "junit:junit:${junitVersion}" - - commonTestCompileOnly "org.mockito:mockito-core:2.10.0" - - jakartaTestImplementation "org.mockito:mockito-core:${mockitoVersion}" - jakartaTestImplementation "jakarta.servlet:jakarta.servlet-api:${jakartaServletApiVersion}" - jakartaTestImplementation "org.springframework.boot:spring-boot-starter-test:${jakartaSpringBootVersion}" - jakartaTestImplementation "org.springframework.boot:spring-boot-starter-web:${jakartaSpringBootVersion}" - jakartaTestImplementation "org.springframework:spring-aop:${jakartaSpringVersion}" - - javaxTestImplementation "org.mockito:mockito-core:2.10.0" - javaxTestImplementation "javax.servlet:javax.servlet-api:${javaxServletApiVersion}" - javaxTestImplementation "org.springframework.boot:spring-boot-starter-test:${javaxSpringBootVersion}" - javaxTestImplementation "org.springframework.boot:spring-boot-starter-web:${javaxSpringBootVersion}" - javaxTestImplementation "org.springframework:spring-aop:${javaxSpringVersion}" -} - -dependencies { - // ensure that the published .pom file includes a dependency on com.bugsnag:bugsnag - // this 'api' dependency has no impact on the compilation of this projects source, - // so we keep it in it's own dependencies block - api project(':bugsnag') -} - -// here is where we merge all of the class outputs into the default classes directory doing this as its own step avoids -// circular dependencies between the sourceSets and their output directories (if they all use 'main.output.classesDirs' -// then jakarta+javax both depend on it as well) -tasks.register('mergeClasses', Copy) { - from sourceSets.common.output.classesDirs - from sourceSets.jakarta.output.classesDirs - from sourceSets.javax.output.classesDirs - - into sourceSets.main.output.classesDirs.asPath -} - -classes.dependsOn('mergeClasses') - -if (project.hasProperty('releasing')) { - publishing { - publications { - Publication(MavenPublication) { - // this is vital: we use the version details from the "javax" side of the project - // this ensures that Gradle considers that as the baseline set of required versions - // allowing old projects that still use Java8 and the javax.servlet packages to use - // bugsnag-java without any secondary artifacts - versionMapping { - usage('java-api') { - fromResolutionOf('compileCommon') - } - usage('java-runtime') { - fromResolutionOf('compileCommon') - } - } - } - } - } -} diff --git a/bugsnag-spring/build.gradle.kts b/bugsnag-spring/build.gradle.kts new file mode 100644 index 00000000..89b66137 --- /dev/null +++ b/bugsnag-spring/build.gradle.kts @@ -0,0 +1,50 @@ +plugins { + `java-library` +} + +repositories { + mavenCentral() +} + +java { + withJavadocJar() + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +val sourceJar by tasks.registering(Jar::class) { + from(sourceSets.main.get().allJava) +} + +// do not move this higher - sourceJar must be registered before we apply common.gradle.kts +apply(from = "../common.gradle.kts") + +dependencies { + implementation(project(":bugsnag")) + + implementation(libs.logback.core) + implementation(libs.slf4j.api) + + implementation(libs.jakarta.servlet.api) + implementation(libs.spring.webmvc) + implementation(libs.springBoot3.boot) + implementation(libs.spring.aop) + + testImplementation(project(":bugsnag").dependencyProject.sourceSets["test"].output) + testImplementation(project(":bugsnag")) + testImplementation(libs.junit) + testImplementation(libs.springBoot3.starter.test) + testImplementation(libs.springBoot3.starter.web) + testImplementation(libs.junit.jupiter) + testCompileOnly(libs.mockito.core.legacy) +} + +/** ---- Publishing config ---- + * Pulls in publishing+signing rules from the shared release.gradle.kts. + * This will create tasks like: + * :bugsnag:publishMavenJavaPublicationToTestRepository + * :bugsnag:publishMavenJavaPublicationToOssrhStagingRepository + */ +apply(from = "${rootProject.projectDir}/release.gradle.kts") + diff --git a/bugsnag-spring/javax/build.gradle b/bugsnag-spring/javax/build.gradle deleted file mode 100644 index edb7f763..00000000 --- a/bugsnag-spring/javax/build.gradle +++ /dev/null @@ -1,41 +0,0 @@ -ext { - springVersion = '5.3.20' - springBootVersion = '2.5.14' -} - -apply plugin: 'java' -apply plugin: 'java-library' - -apply from: '../../common.gradle' - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(8) - } -} - -compileJava { - sourceCompatibility = '1.8' - targetCompatibility = '1.8' -} - -repositories { - mavenCentral() -} - -dependencies { - api project(':bugsnag') - testImplementation project(':bugsnag').sourceSets.test.output - - compileOnly "javax.servlet:javax.servlet-api:${javaxServletApiVersion}" - compileOnly "org.springframework:spring-webmvc:${springVersion}" - compileOnly "org.springframework.boot:spring-boot:${springBootVersion}" - compileOnly "ch.qos.logback:logback-core:${logbackVersion}" - compileOnly "org.slf4j:slf4j-api:${slf4jApiVersion}" - - testImplementation "junit:junit:${junitVersion}" - testImplementation "javax.servlet:javax.servlet-api:${javaxServletApiVersion}" - testImplementation "org.springframework.boot:spring-boot-starter-test:${springBootVersion}" - testImplementation "org.springframework.boot:spring-boot-starter-web:${springBootVersion}" - testImplementation "org.mockito:mockito-core:${mockitoVersion}" -} \ No newline at end of file diff --git a/bugsnag-spring/javax/src/test/resources/logback.xml b/bugsnag-spring/javax/src/test/resources/logback.xml deleted file mode 100644 index 073f1525..00000000 --- a/bugsnag-spring/javax/src/test/resources/logback.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - apiKey - - - - - - - \ No newline at end of file diff --git a/bugsnag-spring/src/common/java/com/bugsnag/BugsnagImportSelector.java b/bugsnag-spring/src/common/java/com/bugsnag/BugsnagImportSelector.java deleted file mode 100644 index 36f10e1a..00000000 --- a/bugsnag-spring/src/common/java/com/bugsnag/BugsnagImportSelector.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.bugsnag; - -import org.springframework.context.annotation.ImportSelector; -import org.springframework.core.SpringVersion; -import org.springframework.core.type.AnnotationMetadata; - -public class BugsnagImportSelector implements ImportSelector { - - private static final String[] SPRING_JAKARTA_CLASSES = { - "com.bugsnag.SpringBootJakartaConfiguration", - "com.bugsnag.JakartaMvcConfiguration", - "com.bugsnag.ScheduledTaskConfiguration" - }; - - private static final String[] SPRING_JAVAX_CLASSES = { - "com.bugsnag.SpringBootJavaxConfiguration", - "com.bugsnag.JavaxMvcConfiguration", - "com.bugsnag.ScheduledTaskConfiguration" - }; - - @Override - public String[] selectImports(AnnotationMetadata importingClassMetadata) { - if (isSpringJakartaCompatible() && isJava17Compatible()) { - return SPRING_JAKARTA_CLASSES; - } - - return SPRING_JAVAX_CLASSES; - } - - private static boolean isSpringJakartaCompatible() { - return getMajorVersion(SpringVersion.getVersion()) >= 6; - } - - private static boolean isJava17Compatible() { - return getMajorVersion(System.getProperty("java.version")) >= 17; - } - - private static int getMajorVersion(String version) { - if (version == null) { - return 0; - } - int firstDot = version.indexOf("."); - String majorVersion; - - if (firstDot == -1) { - majorVersion = version; - } else { - majorVersion = version.substring(0, firstDot); - } - - try { - return Integer.parseInt(majorVersion); - } catch (NumberFormatException nfe) { - return 0; - } - } -} diff --git a/bugsnag-spring/src/common/java/com/bugsnag/ScheduledTaskConfiguration.java b/bugsnag-spring/src/common/java/com/bugsnag/ScheduledTaskConfiguration.java deleted file mode 100644 index 6c9718a9..00000000 --- a/bugsnag-spring/src/common/java/com/bugsnag/ScheduledTaskConfiguration.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.bugsnag; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.aop.framework.AopProxyUtils; -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.annotation.SchedulingConfigurer; -import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.scheduling.config.ScheduledTaskRegistrar; - -import org.springframework.util.ErrorHandler; - -import java.lang.reflect.Field; -import java.util.concurrent.ScheduledExecutorService; - -/** - * Add configuration for reporting unhandled exceptions for scheduled tasks. - */ -@Configuration -class ScheduledTaskConfiguration implements SchedulingConfigurer { - - private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTaskConfiguration.class); - - @Autowired - private Bugsnag bugsnag; - - @Autowired - private ScheduledTaskBeanLocator beanLocator; - - /** - * Add bugsnag error handling to a task scheduler - */ - @Override - public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { - BugsnagScheduledTaskExceptionHandler bugsnagErrorHandler = - new BugsnagScheduledTaskExceptionHandler(bugsnag); - - // Decision process for finding a TaskScheduler, in order of preference: - // - // 1. use the scheduler from the task registrar - // 2. search for a TaskScheduler bean, by type, then by name - // 3. search for a ScheduledExecutorService bean by type, then by name, - // and wrap it in a TaskScheduler - // 4. create our own TaskScheduler - - TaskScheduler registrarScheduler = taskRegistrar.getScheduler(); - TaskScheduler taskScheduler = registrarScheduler != null - ? registrarScheduler : beanLocator.resolveTaskScheduler(); - - if (taskScheduler != null) { - //check if taskSchedular is a proxy - if (AopUtils.isAopProxy(taskScheduler)) { - //if it's a proxy then get the target class and cast as necessary - Class targetClass = AopProxyUtils.ultimateTargetClass(taskScheduler); - if (TaskScheduler.class.isAssignableFrom(targetClass)) { - taskScheduler = (TaskScheduler) AopProxyUtils.getSingletonTarget(taskScheduler); - } - } - configureExistingTaskScheduler(taskScheduler, bugsnagErrorHandler); - } else { - ScheduledExecutorService executorService = beanLocator.resolveScheduledExecutorService(); - taskScheduler = createNewTaskScheduler(executorService, bugsnagErrorHandler); - taskRegistrar.setScheduler(taskScheduler); - } - } - - private TaskScheduler createNewTaskScheduler( - ScheduledExecutorService executorService, - BugsnagScheduledTaskExceptionHandler errorHandler) { - if (executorService != null) { - // create a task scheduler which delegates to the existing Executor - ConcurrentTaskScheduler scheduler = new ConcurrentTaskScheduler(executorService); - scheduler.setErrorHandler(errorHandler); - return scheduler; - } else { - // If no task scheduler has been defined by the application, create one - // and add the bugsnag error handler. - ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); - scheduler.setErrorHandler(errorHandler); - scheduler.initialize(); - return scheduler; - } - } - - /** - * If a task scheduler has been defined by the application, get it so that - * bugsnag error handling can be added. - *

- * Reflection is the simplest way to get and set an error handler - * because the error handler setter is only defined in the concrete classes, - * not the TaskScheduler interface. - * - * @param taskScheduler the task scheduler - */ - private void configureExistingTaskScheduler(TaskScheduler taskScheduler, - BugsnagScheduledTaskExceptionHandler errorHandler) { - try { - Field errorHandlerField = - taskScheduler.getClass().getDeclaredField("errorHandler"); - errorHandlerField.setAccessible(true); - Object existingErrorHandler = errorHandlerField.get(taskScheduler); - - // If an error handler has already been defined then make the Bugsnag handler - // call this afterwards - if (existingErrorHandler instanceof ErrorHandler) { - errorHandler.setExistingErrorHandler((ErrorHandler) existingErrorHandler); - } - - // Add the bugsnag error handler to the scheduler. - errorHandlerField.set(taskScheduler, errorHandler); - } catch (Throwable ex) { - LOGGER.warn("Bugsnag scheduled task exception handler could not be configured"); - } - } -} diff --git a/bugsnag-spring/src/javax/java/com/bugsnag/BugsnagJavaxMvcExceptionHandler.java b/bugsnag-spring/src/javax/java/com/bugsnag/BugsnagJavaxMvcExceptionHandler.java deleted file mode 100644 index 62cbf9ea..00000000 --- a/bugsnag-spring/src/javax/java/com/bugsnag/BugsnagJavaxMvcExceptionHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.bugsnag; - -import com.bugsnag.HandledState.SeverityReasonType; - -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.web.servlet.HandlerExceptionResolver; -import org.springframework.web.servlet.ModelAndView; - -import java.util.Collections; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * Reports uncaught exceptions thrown from handler mapping or execution to Bugsnag - * and then passes the exception to the next handler in the chain. - * - * Set to highest precedence so that it should be called before other exception - * resolvers. - */ -@Order(Ordered.HIGHEST_PRECEDENCE) -class BugsnagJavaxMvcExceptionHandler implements HandlerExceptionResolver { - - private final Bugsnag bugsnag; - - BugsnagJavaxMvcExceptionHandler(final Bugsnag bugsnag) { - this.bugsnag = bugsnag; - } - - @Override - public ModelAndView resolveException(HttpServletRequest request, - HttpServletResponse response, - Object handler, - java.lang.Exception ex) { - - if (bugsnag.getConfig().shouldSendUncaughtExceptions()) { - HandledState handledState = HandledState.newInstance( - SeverityReasonType.REASON_UNHANDLED_EXCEPTION_MIDDLEWARE, - Collections.singletonMap("framework", "Spring"), - Severity.ERROR, - true); - - bugsnag.notify(ex, handledState, Thread.currentThread()); - } - - // Returning null passes the exception onto the next resolver in the chain. - return null; - } -} diff --git a/bugsnag-spring/src/javax/java/com/bugsnag/JavaxMvcConfiguration.java b/bugsnag-spring/src/javax/java/com/bugsnag/JavaxMvcConfiguration.java deleted file mode 100644 index 8ba8e5e8..00000000 --- a/bugsnag-spring/src/javax/java/com/bugsnag/JavaxMvcConfiguration.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.bugsnag; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; - -/** - * If spring-webmvc is loaded, add configuration for reporting unhandled exceptions. - */ -@Configuration -@Conditional(SpringWebMvcLoadedCondition.class) -class JavaxMvcConfiguration implements InitializingBean { - - @Autowired - private Bugsnag bugsnag; - - /** - * Register an exception resolver to send unhandled reports to Bugsnag - * for uncaught exceptions thrown from request handlers. - */ - @Bean - BugsnagJavaxMvcExceptionHandler bugsnagHandlerExceptionResolver() { - return new BugsnagJavaxMvcExceptionHandler(bugsnag); - } - - /** - * Add a callback to assign specified severities for some Spring exceptions. - */ - @Override - public void afterPropertiesSet() { - bugsnag.addCallback(new ExceptionClassCallback()); - } -} diff --git a/bugsnag-spring/src/javax/java/com/bugsnag/SpringBootJavaxConfiguration.java b/bugsnag-spring/src/javax/java/com/bugsnag/SpringBootJavaxConfiguration.java deleted file mode 100644 index 1f63c81d..00000000 --- a/bugsnag-spring/src/javax/java/com/bugsnag/SpringBootJavaxConfiguration.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.bugsnag; - -import com.bugsnag.servlet.javax.BugsnagServletRequestListener; - -import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; - -import javax.servlet.ServletRequestListener; - -/** - * If spring-boot is loaded, add configuration specific to Spring Boot - */ -@Configuration -@Conditional(SpringBootLoadedCondition.class) -class SpringBootJavaxConfiguration extends SpringBootConfiguration { - - /** - * The {@link com.bugsnag.servlet.javax.BugsnagServletContainerInitializer} does not work for Spring Boot, need to - * register the {@link BugsnagServletRequestListener} using a Spring Boot - * {@link ServletListenerRegistrationBean} instead. This adds session tracking and - * automatic servlet request metadata collection. - */ - @Bean - @Conditional(SpringWebMvcLoadedCondition.class) - ServletListenerRegistrationBean listenerRegistrationBean() { - ServletListenerRegistrationBean srb = - new ServletListenerRegistrationBean(); - srb.setListener(new BugsnagServletRequestListener()); - return srb; - } -} diff --git a/bugsnag-spring/src/javaxTest/java/com/bugsnag/ScheduledTaskBeanLocatorTest.java b/bugsnag-spring/src/javaxTest/java/com/bugsnag/ScheduledTaskBeanLocatorTest.java deleted file mode 100644 index 74eb856d..00000000 --- a/bugsnag-spring/src/javaxTest/java/com/bugsnag/ScheduledTaskBeanLocatorTest.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.bugsnag; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.when; - -import com.bugsnag.testapp.springboot.TestSpringBootApplication; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.NoUniqueBeanDefinitionException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.ApplicationContext; -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = TestSpringBootApplication.class) -public class ScheduledTaskBeanLocatorTest { - - @Autowired - private ScheduledTaskBeanLocator beanLocator; - - @MockBean - private ApplicationContext context; - - @Before - public void setUp() { - beanLocator.setApplicationContext(context); - } - - @Test - public void findSchedulerByType() { - ThreadPoolTaskScheduler expected = new ThreadPoolTaskScheduler(); - when(context.getBean(TaskScheduler.class)).thenReturn(expected); - assertEquals(expected, beanLocator.resolveTaskScheduler()); - } - - @Test - public void findSchedulerByName() { - ThreadPoolTaskScheduler expected = new ThreadPoolTaskScheduler(); - Throwable exc = new NoUniqueBeanDefinitionException(TaskScheduler.class); - when(context.getBean(TaskScheduler.class)).thenThrow(exc); - when(context.getBean("taskScheduler", TaskScheduler.class)).thenReturn(expected); - assertEquals(expected, beanLocator.resolveTaskScheduler()); - } - - @Test - public void noTaskSchedulerAvailable() { - assertNull(beanLocator.resolveTaskScheduler()); - } - - @Test - public void findExecutorByType() { - ScheduledExecutorService expected = Executors.newScheduledThreadPool(1); - when(context.getBean(ScheduledExecutorService.class)).thenReturn(expected); - assertEquals(expected, beanLocator.resolveScheduledExecutorService()); - } - - @Test - public void findExecutorByName() { - ScheduledExecutorService expected = Executors.newScheduledThreadPool(4); - Throwable exc = new NoUniqueBeanDefinitionException(ScheduledExecutorService.class); - when(context.getBean(ScheduledExecutorService.class)).thenThrow(exc); - when(context.getBean("taskScheduler", ScheduledExecutorService.class)) - .thenReturn(expected); - assertEquals(expected, beanLocator.resolveScheduledExecutorService()); - } - - @Test - public void noScheduledExecutorAvailable() { - assertNull(beanLocator.resolveScheduledExecutorService()); - } -} diff --git a/bugsnag-spring/src/javaxTest/java/com/bugsnag/ScheduledTaskConfigurationTest.java b/bugsnag-spring/src/javaxTest/java/com/bugsnag/ScheduledTaskConfigurationTest.java deleted file mode 100644 index f619795d..00000000 --- a/bugsnag-spring/src/javaxTest/java/com/bugsnag/ScheduledTaskConfigurationTest.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.bugsnag; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.mockito.Mockito.when; - -import com.bugsnag.testapp.springboot.TestSpringBootApplication; - -import org.aopalliance.intercept.MethodInterceptor; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.beans.factory.NoUniqueBeanDefinitionException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.ApplicationContext; -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.scheduling.config.ScheduledTaskRegistrar; -import org.springframework.test.context.junit4.SpringRunner; - -import java.lang.reflect.Field; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = TestSpringBootApplication.class) -public class ScheduledTaskConfigurationTest { - - @Autowired - private ScheduledTaskConfiguration configuration; - - @Mock - private ScheduledTaskRegistrar registrar; - - @Autowired - private ScheduledTaskBeanLocator beanLocator; - - @MockBean - private ApplicationContext context; - - @Before - public void setUp() { - registrar = new ScheduledTaskRegistrar(); - beanLocator.setApplicationContext(context); - } - - @Test - public void existingSchedulerUsed() { - ThreadPoolTaskScheduler expected = new ThreadPoolTaskScheduler(); - registrar.setScheduler(expected); - configuration.configureTasks(registrar); - assertEquals(expected, registrar.getScheduler()); - } - - @Test - public void noSchedulersAvailable() { - configuration.configureTasks(registrar); - assertTrue(registrar.getScheduler() instanceof ThreadPoolTaskScheduler); - } - - @Test - public void findSchedulerByType() throws NoSuchFieldException, IllegalAccessException { - ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); - when(context.getBean(TaskScheduler.class)).thenReturn(scheduler); - - configuration.configureTasks(registrar); - assertNull(registrar.getScheduler()); - Object errorHandler = accessField(scheduler, "errorHandler"); - assertTrue(errorHandler instanceof BugsnagScheduledTaskExceptionHandler); - } - - @Test - public void findSchedulerByName() throws NoSuchFieldException, IllegalAccessException { - ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); - Throwable exc = new NoUniqueBeanDefinitionException(TaskScheduler.class); - when(context.getBean(TaskScheduler.class)).thenThrow(exc); - when(context.getBean("taskScheduler", TaskScheduler.class)).thenReturn(scheduler); - - configuration.configureTasks(registrar); - assertNull(registrar.getScheduler()); - Object errorHandler = accessField(scheduler, "errorHandler"); - assertTrue(errorHandler instanceof BugsnagScheduledTaskExceptionHandler); - } - - @Test - public void findExecutorByType() throws NoSuchFieldException, IllegalAccessException { - ScheduledExecutorService expected = Executors.newScheduledThreadPool(1); - when(context.getBean(ScheduledExecutorService.class)).thenReturn(expected); - - configuration.configureTasks(registrar); - TaskScheduler scheduler = registrar.getScheduler(); - assertTrue(scheduler instanceof ConcurrentTaskScheduler); - assertEquals(expected, accessField(scheduler, "scheduledExecutor")); - } - - @Test - public void findExecutorByName() throws NoSuchFieldException, IllegalAccessException { - ScheduledExecutorService expected = Executors.newScheduledThreadPool(4); - Throwable exc = new NoUniqueBeanDefinitionException(ScheduledExecutorService.class); - when(context.getBean(ScheduledExecutorService.class)).thenThrow(exc); - when(context.getBean("taskScheduler", ScheduledExecutorService.class)) - .thenReturn(expected); - - configuration.configureTasks(registrar); - TaskScheduler scheduler = registrar.getScheduler(); - assertTrue(scheduler instanceof ConcurrentTaskScheduler); - assertEquals(expected, accessField(scheduler, "scheduledExecutor")); - } - - @Test - public void configureTasks_withProxyWrappedRegistrar() throws NoSuchFieldException, IllegalAccessException { - ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); - when(context.getBean(TaskScheduler.class)).thenReturn(scheduler); - TaskScheduler proxyScheduler = createProxy(scheduler); - registrar.setScheduler(proxyScheduler); - Object errorHandler = accessField(scheduler, "errorHandler"); - assertFalse( - errorHandler instanceof BugsnagScheduledTaskExceptionHandler, - "errorHandler should not be BugsnagScheduledTaskExceptionHandler" - ); - configuration.configureTasks(registrar); - errorHandler = accessField(scheduler, "errorHandler"); - assertTrue( - "errorHandler should be BugsnagScheduledTaskExceptionHandler", - errorHandler instanceof BugsnagScheduledTaskExceptionHandler - ); - } - - private TaskScheduler createProxy(TaskScheduler target) { - ProxyFactory factory = new ProxyFactory(target); - factory.addAdvice((MethodInterceptor) invocation -> invocation.proceed()); - return (TaskScheduler) factory.getProxy(); - } - - private Object accessField(Object object, String fieldName) - throws NoSuchFieldException, IllegalAccessException { - Field field = object.getClass().getDeclaredField(fieldName); - field.setAccessible(true); - return field.get(object); - } -} diff --git a/bugsnag-spring/src/javaxTest/java/com/bugsnag/SpringAsyncTest.java b/bugsnag-spring/src/javaxTest/java/com/bugsnag/SpringAsyncTest.java deleted file mode 100644 index 1bdfa04b..00000000 --- a/bugsnag-spring/src/javaxTest/java/com/bugsnag/SpringAsyncTest.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.bugsnag; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -import com.bugsnag.HandledState.SeverityReasonType; -import com.bugsnag.delivery.Delivery; -import com.bugsnag.testapp.springboot.AsyncService; -import com.bugsnag.testapp.springboot.TestSpringBootApplication; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -import java.util.Collections; - -/** - * Test that a Spring Boot application configured with the - * {@link BugsnagSpringConfiguration} performs as expected. - */ -@RunWith(SpringRunner.class) -@SpringBootTest(classes = TestSpringBootApplication.class) -public class SpringAsyncTest { - - @Autowired - private Bugsnag bugsnag; - - @Autowired - private AsyncService asyncService; - - private Delivery delivery; - - /** - * Initialize test state - */ - @Before - public void setUp() { - delivery = mock(Delivery.class); - bugsnag.setDelivery(delivery); - } - - @Test - public void bugsnagNotifyWhenAsyncVoidReturnTypeException() { - asyncService.throwExceptionVoid(); - - Report report = TestUtils.verifyAndGetReport(delivery); - - // Assert that the exception was detected correctly - assertEquals("Async void test", report.getExceptionMessage()); - assertEquals("java.lang.RuntimeException", report.getExceptionName()); - - // Assert that the severity, severity reason and unhandled values are correct - Assert.assertEquals(Severity.ERROR.getValue(), report.getSeverity()); - assertEquals( - SeverityReasonType.REASON_UNHANDLED_EXCEPTION_MIDDLEWARE.toString(), - report.getSeverityReason().getType()); - assertThat( - report.getSeverityReason().getAttributes(), - is(Collections.singletonMap("framework", "Spring"))); - assertTrue(report.getUnhandled()); - } - - @Test - public void bugsnagNotifyWhenAsyncFutureReturnTypeException() { - asyncService.throwExceptionFuture(); - - Report report = TestUtils.verifyAndGetReport(delivery); - - // Assert that the exception was detected correctly - assertEquals("Async future test", report.getExceptionMessage()); - assertEquals("java.lang.RuntimeException", report.getExceptionName()); - - // Assert that the severity, severity reason and unhandled values are correct - assertEquals(Severity.ERROR.getValue(), report.getSeverity()); - assertEquals( - SeverityReasonType.REASON_UNHANDLED_EXCEPTION_MIDDLEWARE.toString(), - report.getSeverityReason().getType()); - assertThat( - report.getSeverityReason().getAttributes(), - is(Collections.singletonMap("framework", "Spring"))); - assertTrue(report.getUnhandled()); - } -} diff --git a/bugsnag-spring/src/javaxTest/java/com/bugsnag/SpringMvcTest.java b/bugsnag-spring/src/javaxTest/java/com/bugsnag/SpringMvcTest.java deleted file mode 100644 index d426ba01..00000000 --- a/bugsnag-spring/src/javaxTest/java/com/bugsnag/SpringMvcTest.java +++ /dev/null @@ -1,282 +0,0 @@ -package com.bugsnag; - -import static com.bugsnag.TestUtils.anyMapOf; -import static com.bugsnag.TestUtils.verifyAndGetReport; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import com.bugsnag.HandledState.SeverityReasonType; -import com.bugsnag.callbacks.Callback; -import com.bugsnag.delivery.Delivery; -import com.bugsnag.serialization.Serializer; -import com.bugsnag.testapp.springboot.TestSpringBootApplication; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.SpringBootVersion; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.core.SpringVersion; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.test.context.junit4.SpringRunner; - -import java.lang.reflect.Field; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; - -/** - * Test that a Spring Boot application configured with the - * {@link BugsnagSpringConfiguration} performs as expected. - */ -@RunWith(SpringRunner.class) -@SpringBootTest( - classes = TestSpringBootApplication.class, - webEnvironment = WebEnvironment.RANDOM_PORT) -public class SpringMvcTest { - - @LocalServerPort - private int randomServerPort; - - @Autowired - private TestRestTemplate restTemplate; - - @Autowired - private Bugsnag bugsnag; - - private Delivery delivery; - - private long sessionsStartedBeforeTest; - - /** - * Initialize test state - */ - @Before - public void setUp() { - delivery = mock(Delivery.class); - - bugsnag.setDelivery(delivery); - bugsnag.getConfig().setSendUncaughtExceptions(true); - bugsnag.getConfig().setAutoCaptureSessions(true); - - // Cannot reset the session count on the bugsnag bean for each test, so note - // the current session count before the test starts instead. - sessionsStartedBeforeTest = getSessionCount(); - } - - @Test - public void bugsnagNotifyWhenUncaughtControllerException() { - callRuntimeExceptionEndpoint(); - - Report report = verifyAndGetReport(delivery); - - // Assert that the exception was detected correctly - assertEquals("Test", report.getExceptionMessage()); - assertEquals("java.lang.RuntimeException", report.getExceptionName()); - - // Assert that the severity, severity reason and unhandled values are correct - Assert.assertEquals(Severity.ERROR.getValue(), report.getSeverity()); - assertEquals( - SeverityReasonType.REASON_UNHANDLED_EXCEPTION_MIDDLEWARE.toString(), - report.getSeverityReason().getType()); - assertThat( - report.getSeverityReason().getAttributes(), - is(Collections.singletonMap("framework", "Spring"))); - assertTrue(report.getUnhandled()); - } - - @Test - public void noBugsnagNotifyWhenSendUncaughtExceptionsFalse() { - bugsnag.getConfig().setSendUncaughtExceptions(false); - - callRuntimeExceptionEndpoint(); - - verifyNoReport(); - } - - @Test - public void bugsnagSessionStartedWhenAutoCaptureSessions() { - callRuntimeExceptionEndpoint(); - - assertSessionsStarted(1); - } - - @Test - public void noBugsnagSessionStartedWhenAutoCaptureSessionsFalse() { - bugsnag.getConfig().setAutoCaptureSessions(false); - - callRuntimeExceptionEndpoint(); - - assertSessionsStarted(0); - } - - @Test - public void requestMetadataSetCorrectly() { - callRuntimeExceptionEndpoint(); - - Report report = verifyAndGetReport(delivery); - - // Check that the context is set to the HTTP method and URI of the endpoint - assertEquals("GET /throw-runtime-exception", report.getContext()); - - // Check that the request metadata is set as expected - @SuppressWarnings(value = "unchecked") Map requestMetadata = - (Map) report.getMetaData().get("request"); - assertEquals("http://localhost:" + randomServerPort + "/throw-runtime-exception", - requestMetadata.get("url")); - assertEquals("GET", requestMetadata.get("method")); - assertEquals("127.0.0.1", requestMetadata.get("clientIp")); - - // Assert that the request params are as expected - @SuppressWarnings(value = "unchecked") Map params = - (Map) requestMetadata.get("params"); - assertEquals("paramVal1", params.get("param1")[0]); - assertEquals("paramVal2", params.get("param2")[0]); - - // Assert that the request headers are as expected, including headers with - // multiple values represented as a comma-separated string. - @SuppressWarnings(value = "unchecked") Map headers = - (Map) requestMetadata.get("headers"); - assertEquals("header1Val1,header1Val2", headers.get("header1")); - assertEquals("header2Val1", headers.get("header2")); - } - - @Test - @SuppressWarnings("unchecked") - public void springVersionSetCorrectly() { - callRuntimeExceptionEndpoint(); - - Report report = verifyAndGetReport(delivery); - - // Check that the Spring version is set as expected - Map deviceMetadata = report.getDevice(); - Map runtimeVersions = - (Map) deviceMetadata.get("runtimeVersions"); - assertEquals(SpringVersion.getVersion(), runtimeVersions.get("springFramework")); - assertEquals(SpringBootVersion.getVersion(), runtimeVersions.get("springBoot")); - } - - @Test - public void unhandledTypeMismatchExceptionSeverityInfo() { - callUnhandledTypeMismatchExceptionEndpoint(); - - Report report = verifyAndGetReport(delivery); - - assertTrue(report.getUnhandled()); - assertEquals("info", report.getSeverity()); - assertEquals("exceptionClass", report.getSeverityReason().getType()); - assertThat(report.getSeverityReason().getAttributes(), - is(Collections.singletonMap("exceptionClass", "TypeMismatchException"))); - } - - @Test - public void unhandledTypeMismatchExceptionCallbackSeverity() - throws IllegalAccessException, NoSuchFieldException { - Report report; - Callback callback = new Callback() { - @Override - public void beforeNotify(Report report) { - report.setSeverity(Severity.WARNING); - } - }; - - try { - bugsnag.addCallback(callback); - - callUnhandledTypeMismatchExceptionEndpoint(); - - report = verifyAndGetReport(delivery); - } finally { - // Remove the callback via reflection so that subsequent tests do not use it - Field callbacksField = Configuration.class.getDeclaredField("callbacks"); - @SuppressWarnings(value = "unchecked") Collection callbacks = - (Collection) callbacksField.get(bugsnag.getConfig()); - callbacks.remove(callback); - } - - assertTrue(report.getUnhandled()); - assertEquals("warning", report.getSeverity()); - assertEquals("userCallbackSetSeverity", report.getSeverityReason().getType()); - } - - @Test - public void handledTypeMismatchExceptionUserSeverity() { - callHandledTypeMismatchExceptionUserSeverityEndpoint(); - - Report report = verifyAndGetReport(delivery); - - assertFalse(report.getUnhandled()); - assertEquals("warning", report.getSeverity()); - assertEquals("userSpecifiedSeverity", report.getSeverityReason().getType()); - assertThat(report.getSeverityReason().getAttributes(), is(Collections.EMPTY_MAP)); - } - - @Test - public void handledTypeMismatchExceptionCallbackSeverity() { - callHandledTypeMismatchExceptionCallbackSeverityEndpoint(); - - Report report = verifyAndGetReport(delivery); - - assertFalse(report.getUnhandled()); - assertEquals("warning", report.getSeverity()); - assertEquals("userCallbackSetSeverity", report.getSeverityReason().getType()); - } - - private void callUnhandledTypeMismatchExceptionEndpoint() { - this.restTemplate.getForEntity( - "/throw-type-mismatch-exception", String.class); - } - - private void callHandledTypeMismatchExceptionUserSeverityEndpoint() { - this.restTemplate.getForEntity( - "/handled-type-mismatch-exception-user-severity", String.class); - } - - private void callHandledTypeMismatchExceptionCallbackSeverityEndpoint() { - this.restTemplate.getForEntity( - "/handled-type-mismatch-exception-callback-severity", String.class); - } - - private void callRuntimeExceptionEndpoint() { - HttpHeaders headers = new HttpHeaders(); - headers.add("header1", "header1Val1"); - headers.add("header1", "header1Val2"); - headers.add("header2", "header2Val1"); - HttpEntity entity = new HttpEntity("parameters", headers); - this.restTemplate.exchange( - "/throw-runtime-exception?param1=paramVal1¶m2=paramVal2", - HttpMethod.GET, - entity, - String.class); - } - - private void verifyNoReport() { - verify(delivery, times(0)).deliver( - any(Serializer.class), - any(), - anyMapOf(String.class, String.class)); - } - - private void assertSessionsStarted(int sessionsStarted) { - assertEquals(sessionsStartedBeforeTest + sessionsStarted, getSessionCount()); - } - - private long getSessionCount() { - return bugsnag.getSessionTracker().getBatchCount() != null - ? bugsnag.getSessionTracker().getBatchCount().getSessionsStarted() : 0; - } -} diff --git a/bugsnag-spring/src/javaxTest/java/com/bugsnag/SpringScheduledTaskTest.java b/bugsnag-spring/src/javaxTest/java/com/bugsnag/SpringScheduledTaskTest.java deleted file mode 100644 index 7a86ff61..00000000 --- a/bugsnag-spring/src/javaxTest/java/com/bugsnag/SpringScheduledTaskTest.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.bugsnag; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import com.bugsnag.HandledState.SeverityReasonType; -import com.bugsnag.delivery.Delivery; -import com.bugsnag.testapp.springboot.TestSpringBootApplication; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.util.ErrorHandler; - -import java.util.Collections; -import java.util.concurrent.ExecutionException; - -/** - * Test that a Spring Boot application configured with the - * {@link BugsnagSpringConfiguration} performs as expected. - */ -@RunWith(SpringRunner.class) -@SpringBootTest(classes = TestSpringBootApplication.class) -public class SpringScheduledTaskTest { - - @Autowired - private Bugsnag bugsnag; - - @Autowired - private ThreadPoolTaskScheduler scheduler; - - @MockBean - private ErrorHandler mockErrorHandler; - - private Delivery delivery; - - /** - * Initialize test state - */ - @Before - public void setUp() { - delivery = mock(Delivery.class); - bugsnag.setDelivery(delivery); - } - - @Test - public void bugsnagNotifyWhenScheduledTaskException() - throws ExecutionException, InterruptedException { - - // The task to schedule - Runnable exampleRunnable = new Runnable() { - @Override - public void run() { - throw new RuntimeException("Scheduled test"); - } - }; - - // Run the task now and wait for it to finish - scheduler.submit(exampleRunnable).get(); - - Report report = TestUtils.verifyAndGetReport(delivery); - - // Assert that the exception was detected correctly - assertEquals("Scheduled test", report.getExceptionMessage()); - assertEquals("java.lang.RuntimeException", report.getExceptionName()); - - // Assert that the severity, severity reason and unhandled values are correct - Assert.assertEquals(Severity.ERROR.getValue(), report.getSeverity()); - assertEquals( - SeverityReasonType.REASON_UNHANDLED_EXCEPTION_MIDDLEWARE.toString(), - report.getSeverityReason().getType()); - assertThat( - report.getSeverityReason().getAttributes(), - is(Collections.singletonMap("framework", "Spring"))); - assertTrue(report.getUnhandled()); - - // Assert that the exception is passed to an existing exception handler - ArgumentCaptor exceptionCaptor = - ArgumentCaptor.forClass(RuntimeException.class); - verify(mockErrorHandler, times(1)).handleError(exceptionCaptor.capture()); - assertEquals("Scheduled test", exceptionCaptor.getValue().getMessage()); - } -} diff --git a/bugsnag-spring/src/javaxTest/java/com/bugsnag/testapp/springboot/AsyncService.java b/bugsnag-spring/src/javaxTest/java/com/bugsnag/testapp/springboot/AsyncService.java deleted file mode 100644 index 54376bac..00000000 --- a/bugsnag-spring/src/javaxTest/java/com/bugsnag/testapp/springboot/AsyncService.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.bugsnag.testapp.springboot; - -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; - -import java.util.concurrent.Future; - -@Service -public class AsyncService { - @Async - public void throwExceptionVoid() { - throw new RuntimeException("Async void test"); - } - - @Async - public Future throwExceptionFuture() { - throw new RuntimeException("Async future test"); - } -} diff --git a/bugsnag-spring/src/javaxTest/java/com/bugsnag/testapp/springboot/TestConfiguration.java b/bugsnag-spring/src/javaxTest/java/com/bugsnag/testapp/springboot/TestConfiguration.java deleted file mode 100644 index c1691243..00000000 --- a/bugsnag-spring/src/javaxTest/java/com/bugsnag/testapp/springboot/TestConfiguration.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.bugsnag.testapp.springboot; - -import com.bugsnag.Bugsnag; -import com.bugsnag.BugsnagAsyncExceptionHandler; -import com.bugsnag.BugsnagSpringConfiguration; - -import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.scheduling.annotation.AsyncConfigurerSupport; -import org.springframework.scheduling.annotation.SchedulingConfigurer; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.scheduling.config.ScheduledTaskRegistrar; -import org.springframework.util.ErrorHandler; - -/** - * This test configuration loads the BugsnagSpringConfiguration - * that will be used for real Spring bugsnag integration. - */ -@Configuration -@Import(BugsnagSpringConfiguration.class) -public class TestConfiguration extends AsyncConfigurerSupport implements SchedulingConfigurer { - - @Autowired(required = false) - private ErrorHandler scheduledTaskErrorHandler; - - @Bean - public Bugsnag bugsnag() { - return new Bugsnag("apiKey"); - } - - @Bean - ThreadPoolTaskScheduler scheduler() { - ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); - taskScheduler.setErrorHandler(scheduledTaskErrorHandler); - return taskScheduler; - } - - @Override - public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { - taskRegistrar.setScheduler(scheduler()); - } - - @Override - public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { - return new BugsnagAsyncExceptionHandler(bugsnag()); - } -} diff --git a/bugsnag-spring/src/javaxTest/java/com/bugsnag/testapp/springboot/TestController.java b/bugsnag-spring/src/javaxTest/java/com/bugsnag/testapp/springboot/TestController.java deleted file mode 100644 index 9d0091b5..00000000 --- a/bugsnag-spring/src/javaxTest/java/com/bugsnag/testapp/springboot/TestController.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.bugsnag.testapp.springboot; - -import com.bugsnag.Bugsnag; -import com.bugsnag.Report; -import com.bugsnag.Severity; -import com.bugsnag.callbacks.Callback; - -import org.springframework.beans.TypeMismatchException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class TestController { - - @Autowired - private Bugsnag bugsnag; - - /** - * Throw a runtime exception - */ - @RequestMapping("/throw-runtime-exception") - public void throwRuntimeException() { - throw new RuntimeException("Test"); - } - - /** - * Throw an exception where the severity reason is exceptionClass - */ - @RequestMapping("/throw-type-mismatch-exception") - public void throwTypeMismatchException() { - throw new TypeMismatchException("Test", String.class); - } - - /** - * Report a handled exception where the severity reason is exceptionClass - */ - @RequestMapping("/handled-type-mismatch-exception") - public void handledTypeMismatchException() { - try { - throw new TypeMismatchException("Test", String.class); - } catch (TypeMismatchException ex) { - bugsnag.notify(ex); - } - } - - /** - * Report a handled exception where the severity is set in the notify call - */ - @RequestMapping("/handled-type-mismatch-exception-user-severity") - public void handledTypeMismatchExceptionUserSeverity() { - try { - throw new TypeMismatchException("Test", String.class); - } catch (TypeMismatchException ex) { - bugsnag.notify(ex, Severity.WARNING); - } - } - - /** - * Report a handled exception where the severity reason is set in a callback - */ - @RequestMapping("/handled-type-mismatch-exception-callback-severity") - public void handledTypeMismatchExceptionCallbackSeverity() { - try { - throw new TypeMismatchException("Test", String.class); - } catch (TypeMismatchException ex) { - bugsnag.notify(ex, new Callback() { - @Override - public void beforeNotify(Report report) { - report.setSeverity(Severity.WARNING); - } - }); - } - } -} diff --git a/bugsnag-spring/src/javaxTest/java/com/bugsnag/testapp/springboot/TestSpringBootApplication.java b/bugsnag-spring/src/javaxTest/java/com/bugsnag/testapp/springboot/TestSpringBootApplication.java deleted file mode 100644 index f02cde84..00000000 --- a/bugsnag-spring/src/javaxTest/java/com/bugsnag/testapp/springboot/TestSpringBootApplication.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.bugsnag.testapp.springboot; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.scheduling.annotation.EnableAsync; -import org.springframework.scheduling.annotation.EnableScheduling; - -@SpringBootApplication -@EnableScheduling -@EnableAsync -public class TestSpringBootApplication { - public static void main(String[] args) { - SpringApplication.run(TestSpringBootApplication.class, args); - } -} diff --git a/bugsnag-spring/src/common/java/com/bugsnag/BugsnagAsyncExceptionHandler.java b/bugsnag-spring/src/main/java/com/bugsnag/BugsnagAsyncExceptionHandler.java similarity index 100% rename from bugsnag-spring/src/common/java/com/bugsnag/BugsnagAsyncExceptionHandler.java rename to bugsnag-spring/src/main/java/com/bugsnag/BugsnagAsyncExceptionHandler.java diff --git a/bugsnag-spring/src/jakarta/java/com/bugsnag/BugsnagJakartaMvcExceptionHandler.java b/bugsnag-spring/src/main/java/com/bugsnag/BugsnagJakartaMvcExceptionHandler.java similarity index 100% rename from bugsnag-spring/src/jakarta/java/com/bugsnag/BugsnagJakartaMvcExceptionHandler.java rename to bugsnag-spring/src/main/java/com/bugsnag/BugsnagJakartaMvcExceptionHandler.java diff --git a/bugsnag-spring/src/common/java/com/bugsnag/BugsnagScheduledTaskExceptionHandler.java b/bugsnag-spring/src/main/java/com/bugsnag/BugsnagScheduledTaskExceptionHandler.java similarity index 100% rename from bugsnag-spring/src/common/java/com/bugsnag/BugsnagScheduledTaskExceptionHandler.java rename to bugsnag-spring/src/main/java/com/bugsnag/BugsnagScheduledTaskExceptionHandler.java diff --git a/bugsnag-spring/src/common/java/com/bugsnag/BugsnagSpringConfiguration.java b/bugsnag-spring/src/main/java/com/bugsnag/BugsnagSpringConfiguration.java similarity index 96% rename from bugsnag-spring/src/common/java/com/bugsnag/BugsnagSpringConfiguration.java rename to bugsnag-spring/src/main/java/com/bugsnag/BugsnagSpringConfiguration.java index 86d503ef..36f70550 100644 --- a/bugsnag-spring/src/common/java/com/bugsnag/BugsnagSpringConfiguration.java +++ b/bugsnag-spring/src/main/java/com/bugsnag/BugsnagSpringConfiguration.java @@ -15,7 +15,7 @@ * Configuration to integrate Bugsnag with Spring. */ @Configuration -@Import(BugsnagImportSelector.class) +@Import({SpringBootJakartaConfiguration.class, JakartaMvcConfiguration.class, ScheduledTaskConfiguration.class}) public class BugsnagSpringConfiguration implements InitializingBean { @Autowired diff --git a/bugsnag-spring/src/common/java/com/bugsnag/ExceptionClassCallback.java b/bugsnag-spring/src/main/java/com/bugsnag/ExceptionClassCallback.java similarity index 100% rename from bugsnag-spring/src/common/java/com/bugsnag/ExceptionClassCallback.java rename to bugsnag-spring/src/main/java/com/bugsnag/ExceptionClassCallback.java diff --git a/bugsnag-spring/src/jakarta/java/com/bugsnag/JakartaMvcConfiguration.java b/bugsnag-spring/src/main/java/com/bugsnag/JakartaMvcConfiguration.java similarity index 100% rename from bugsnag-spring/src/jakarta/java/com/bugsnag/JakartaMvcConfiguration.java rename to bugsnag-spring/src/main/java/com/bugsnag/JakartaMvcConfiguration.java diff --git a/bugsnag-spring/src/common/java/com/bugsnag/ScheduledTaskBeanLocator.java b/bugsnag-spring/src/main/java/com/bugsnag/ScheduledTaskBeanLocator.java similarity index 100% rename from bugsnag-spring/src/common/java/com/bugsnag/ScheduledTaskBeanLocator.java rename to bugsnag-spring/src/main/java/com/bugsnag/ScheduledTaskBeanLocator.java diff --git a/bugsnag-spring/src/main/java/com/bugsnag/ScheduledTaskConfiguration.java b/bugsnag-spring/src/main/java/com/bugsnag/ScheduledTaskConfiguration.java new file mode 100644 index 00000000..9188d7f9 --- /dev/null +++ b/bugsnag-spring/src/main/java/com/bugsnag/ScheduledTaskConfiguration.java @@ -0,0 +1,197 @@ +package com.bugsnag; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.aop.framework.AopProxyUtils; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; +import org.springframework.util.ErrorHandler; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.concurrent.ScheduledExecutorService; + +/** + * Add configuration for reporting unhandled exceptions for scheduled tasks. + */ +@Configuration +class ScheduledTaskConfiguration implements SchedulingConfigurer { + + private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTaskConfiguration.class); + + @Autowired + private Bugsnag bugsnag; + + @Autowired + private ScheduledTaskBeanLocator beanLocator; + + /** + * Optional: if the app defines a dedicated ErrorHandler bean for scheduled tasks + * (e.g. your @MockBean(name = "scheduledTaskErrorHandler") in tests), we can + * still chain it when we replace or wrap the scheduler. + */ + @Autowired(required = false) + @Qualifier("scheduledTaskErrorHandler") + private ErrorHandler scheduledTaskErrorHandlerBean; + + /** + * Add Bugsnag error handling to the task scheduler being used by Spring. + */ + @Override + public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { + BugsnagScheduledTaskExceptionHandler bugsnagErrorHandler = + new BugsnagScheduledTaskExceptionHandler(bugsnag); + + // Decision process for finding a TaskScheduler, in order of preference: + // 1. use the scheduler from the task registrar + // 2. search for a TaskScheduler bean, by type, then by name + // 3. search for a ScheduledExecutorService bean by type, then by name, and wrap it + // 4. create our own TaskScheduler + TaskScheduler registrarScheduler = taskRegistrar.getScheduler(); + TaskScheduler taskScheduler = registrarScheduler != null + ? registrarScheduler + : beanLocator.resolveTaskScheduler(); + + if (taskScheduler != null) { + // Spring Boot 3 creates a TaskSchedulerRouter which cannot be configured. + // In this case, create our own scheduler instead (but preserve any bean-level handler). + String schedulerClassName = taskScheduler.getClass().getName(); + if (schedulerClassName.equals("org.springframework.scheduling.config.TaskSchedulerRouter")) { + ScheduledExecutorService executorService = beanLocator.resolveScheduledExecutorService(); + chainExistingBeanHandlerIfPresent(bugsnagErrorHandler); + taskScheduler = createNewTaskScheduler(executorService, bugsnagErrorHandler); + taskRegistrar.setScheduler(taskScheduler); + return; + } + + // If it's a proxy, unwrap to the target to allow reflection / method calls. + if (AopUtils.isAopProxy(taskScheduler)) { + Class targetClass = AopProxyUtils.ultimateTargetClass(taskScheduler); + if (TaskScheduler.class.isAssignableFrom(targetClass)) { + TaskScheduler target = (TaskScheduler) AopProxyUtils.getSingletonTarget(taskScheduler); + if (target != null) { + taskScheduler = target; + } + } + } + + configureExistingTaskScheduler(taskScheduler, bugsnagErrorHandler); + } else { + // No scheduler has been defined by the application, create one and add the Bugsnag error handler. + ScheduledExecutorService executorService = beanLocator.resolveScheduledExecutorService(); + chainExistingBeanHandlerIfPresent(bugsnagErrorHandler); + taskScheduler = createNewTaskScheduler(executorService, bugsnagErrorHandler); + taskRegistrar.setScheduler(taskScheduler); + } + } + + private TaskScheduler createNewTaskScheduler( + ScheduledExecutorService executorService, + BugsnagScheduledTaskExceptionHandler errorHandler + ) { + if (executorService != null) { + // Create a task scheduler which delegates to the existing Executor + ConcurrentTaskScheduler scheduler = new ConcurrentTaskScheduler(executorService); + scheduler.setErrorHandler(errorHandler); + return scheduler; + } else { + // If no task scheduler has been defined by the application, create one and add the Bugsnag error handler. + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + scheduler.setErrorHandler(errorHandler); + scheduler.initialize(); + return scheduler; + } + } + + /** + * If a task scheduler has been defined by the application, configure it so that Bugsnag error handling is added. + * We first capture any existing ErrorHandler (e.g. your mock bean), chain it into the Bugsnag handler, + * then set the Bugsnag handler via setter if available (Boot 3+) or via field reflection. + */ + private void configureExistingTaskScheduler( + TaskScheduler taskScheduler, + BugsnagScheduledTaskExceptionHandler errorHandler + ) { + // (1) Capture whatever handler is already configured on the scheduler + ErrorHandler existing = extractExistingErrorHandler(taskScheduler); + if (existing != null) { + errorHandler.setExistingErrorHandler(existing); + } else if (scheduledTaskErrorHandlerBean != null) { + // Fallback: chain the bean-level handler if the scheduler didn't have one yet + errorHandler.setExistingErrorHandler(scheduledTaskErrorHandlerBean); + } + + // (2) Install the Bugsnag handler via public setter if available, else via private field + if (trySetErrorHandlerViaMethod(taskScheduler, errorHandler)) { + return; + } + trySetErrorHandlerViaField(taskScheduler, errorHandler); + } + + /** + * Chain the dedicated bean-level handler if present (useful when we replace the scheduler). + */ + private void chainExistingBeanHandlerIfPresent(BugsnagScheduledTaskExceptionHandler errorHandler) { + if (scheduledTaskErrorHandlerBean != null) { + errorHandler.setExistingErrorHandler(scheduledTaskErrorHandlerBean); + } + } + + /** + * Prefer a public getter if present; otherwise fall back to private field. + */ + private ErrorHandler extractExistingErrorHandler(TaskScheduler taskScheduler) { + // Try public getter (present on ThreadPoolTaskScheduler et al.) + try { + Method getter = taskScheduler.getClass().getMethod("getErrorHandler"); + Object val = getter.invoke(taskScheduler); + if (val instanceof ErrorHandler) { + return (ErrorHandler) val; + } + } catch (Throwable ignore) { + // no-op + } + + // Fall back to private field access + try { + Field fld = taskScheduler.getClass().getDeclaredField("errorHandler"); + fld.setAccessible(true); + Object val = fld.get(taskScheduler); + if (val instanceof ErrorHandler) { + return (ErrorHandler) val; + } + } catch (Throwable ignore) { + // no-op + } + + return null; + } + + private boolean trySetErrorHandlerViaMethod(TaskScheduler taskScheduler, ErrorHandler handler) { + try { + Method setter = taskScheduler.getClass().getMethod("setErrorHandler", ErrorHandler.class); + setter.invoke(taskScheduler, handler); + return true; + } catch (Throwable ex) { + return false; + } + } + + private boolean trySetErrorHandlerViaField(TaskScheduler taskScheduler, ErrorHandler handler) { + try { + Field fld = taskScheduler.getClass().getDeclaredField("errorHandler"); + fld.setAccessible(true); + fld.set(taskScheduler, handler); + return true; + } catch (Throwable ex) { + return false; + } + } +} diff --git a/bugsnag-spring/src/common/java/com/bugsnag/SpringBootConfiguration.java b/bugsnag-spring/src/main/java/com/bugsnag/SpringBootConfiguration.java similarity index 100% rename from bugsnag-spring/src/common/java/com/bugsnag/SpringBootConfiguration.java rename to bugsnag-spring/src/main/java/com/bugsnag/SpringBootConfiguration.java diff --git a/bugsnag-spring/src/jakarta/java/com/bugsnag/SpringBootJakartaConfiguration.java b/bugsnag-spring/src/main/java/com/bugsnag/SpringBootJakartaConfiguration.java similarity index 78% rename from bugsnag-spring/src/jakarta/java/com/bugsnag/SpringBootJakartaConfiguration.java rename to bugsnag-spring/src/main/java/com/bugsnag/SpringBootJakartaConfiguration.java index c9f0d413..06e02edf 100644 --- a/bugsnag-spring/src/jakarta/java/com/bugsnag/SpringBootJakartaConfiguration.java +++ b/bugsnag-spring/src/main/java/com/bugsnag/SpringBootJakartaConfiguration.java @@ -16,9 +16,8 @@ class SpringBootJakartaConfiguration extends SpringBootConfiguration { /** - * The {@link com.bugsnag.servlet.javax.BugsnagServletContainerInitializer} does not work for Spring Boot, need to - * register the {@link BugsnagServletRequestListener} using a Spring Boot - * {@link ServletListenerRegistrationBean} instead. This adds session tracking and + * Spring Boot requires manual registration of the {@link BugsnagServletRequestListener} using a Spring Boot + * {@link ServletListenerRegistrationBean}. This adds session tracking and * automatic servlet request metadata collection. */ @Bean diff --git a/bugsnag-spring/src/common/java/com/bugsnag/SpringBootLoadedCondition.java b/bugsnag-spring/src/main/java/com/bugsnag/SpringBootLoadedCondition.java similarity index 100% rename from bugsnag-spring/src/common/java/com/bugsnag/SpringBootLoadedCondition.java rename to bugsnag-spring/src/main/java/com/bugsnag/SpringBootLoadedCondition.java diff --git a/bugsnag-spring/src/common/java/com/bugsnag/SpringWebMvcLoadedCondition.java b/bugsnag-spring/src/main/java/com/bugsnag/SpringWebMvcLoadedCondition.java similarity index 100% rename from bugsnag-spring/src/common/java/com/bugsnag/SpringWebMvcLoadedCondition.java rename to bugsnag-spring/src/main/java/com/bugsnag/SpringWebMvcLoadedCondition.java diff --git a/bugsnag-spring/src/jakartaTest/java/com/bugsnag/NotifierTest.java b/bugsnag-spring/src/test/java/com/bugsnag/NotifierTest.java similarity index 100% rename from bugsnag-spring/src/jakartaTest/java/com/bugsnag/NotifierTest.java rename to bugsnag-spring/src/test/java/com/bugsnag/NotifierTest.java diff --git a/bugsnag-spring/src/jakartaTest/java/com/bugsnag/ScheduledTaskBeanLocatorTest.java b/bugsnag-spring/src/test/java/com/bugsnag/ScheduledTaskBeanLocatorTest.java similarity index 100% rename from bugsnag-spring/src/jakartaTest/java/com/bugsnag/ScheduledTaskBeanLocatorTest.java rename to bugsnag-spring/src/test/java/com/bugsnag/ScheduledTaskBeanLocatorTest.java diff --git a/bugsnag-spring/src/jakartaTest/java/com/bugsnag/ScheduledTaskConfigurationTest.java b/bugsnag-spring/src/test/java/com/bugsnag/ScheduledTaskConfigurationTest.java similarity index 100% rename from bugsnag-spring/src/jakartaTest/java/com/bugsnag/ScheduledTaskConfigurationTest.java rename to bugsnag-spring/src/test/java/com/bugsnag/ScheduledTaskConfigurationTest.java diff --git a/bugsnag-spring/src/jakartaTest/java/com/bugsnag/SpringAsyncTest.java b/bugsnag-spring/src/test/java/com/bugsnag/SpringAsyncTest.java similarity index 100% rename from bugsnag-spring/src/jakartaTest/java/com/bugsnag/SpringAsyncTest.java rename to bugsnag-spring/src/test/java/com/bugsnag/SpringAsyncTest.java diff --git a/bugsnag-spring/src/jakartaTest/java/com/bugsnag/SpringMvcTest.java b/bugsnag-spring/src/test/java/com/bugsnag/SpringMvcTest.java similarity index 99% rename from bugsnag-spring/src/jakartaTest/java/com/bugsnag/SpringMvcTest.java rename to bugsnag-spring/src/test/java/com/bugsnag/SpringMvcTest.java index ed03f19f..6acb31a1 100644 --- a/bugsnag-spring/src/jakartaTest/java/com/bugsnag/SpringMvcTest.java +++ b/bugsnag-spring/src/test/java/com/bugsnag/SpringMvcTest.java @@ -136,7 +136,7 @@ public void requestMetadataSetCorrectly() { // Check that the request metadata is set as expected @SuppressWarnings(value = "unchecked") Map requestMetadata = - (Map) report.getMetaData().get("request"); + (Map) report.getMetadata().get("request"); assertEquals("http://localhost:" + randomServerPort + "/throw-runtime-exception", requestMetadata.get("url")); assertEquals("GET", requestMetadata.get("method")); diff --git a/bugsnag-spring/src/jakartaTest/java/com/bugsnag/SpringScheduledTaskTest.java b/bugsnag-spring/src/test/java/com/bugsnag/SpringScheduledTaskTest.java similarity index 100% rename from bugsnag-spring/src/jakartaTest/java/com/bugsnag/SpringScheduledTaskTest.java rename to bugsnag-spring/src/test/java/com/bugsnag/SpringScheduledTaskTest.java diff --git a/bugsnag-spring/src/commonTest/java/com/bugsnag/TestUtils.java b/bugsnag-spring/src/test/java/com/bugsnag/TestUtils.java similarity index 100% rename from bugsnag-spring/src/commonTest/java/com/bugsnag/TestUtils.java rename to bugsnag-spring/src/test/java/com/bugsnag/TestUtils.java diff --git a/bugsnag-spring/src/jakartaTest/java/com/bugsnag/testapp/springboot/AsyncService.java b/bugsnag-spring/src/test/java/com/bugsnag/testapp/springboot/AsyncService.java similarity index 100% rename from bugsnag-spring/src/jakartaTest/java/com/bugsnag/testapp/springboot/AsyncService.java rename to bugsnag-spring/src/test/java/com/bugsnag/testapp/springboot/AsyncService.java diff --git a/bugsnag-spring/src/jakartaTest/java/com/bugsnag/testapp/springboot/TestConfiguration.java b/bugsnag-spring/src/test/java/com/bugsnag/testapp/springboot/TestConfiguration.java similarity index 100% rename from bugsnag-spring/src/jakartaTest/java/com/bugsnag/testapp/springboot/TestConfiguration.java rename to bugsnag-spring/src/test/java/com/bugsnag/testapp/springboot/TestConfiguration.java diff --git a/bugsnag-spring/src/jakartaTest/java/com/bugsnag/testapp/springboot/TestController.java b/bugsnag-spring/src/test/java/com/bugsnag/testapp/springboot/TestController.java similarity index 100% rename from bugsnag-spring/src/jakartaTest/java/com/bugsnag/testapp/springboot/TestController.java rename to bugsnag-spring/src/test/java/com/bugsnag/testapp/springboot/TestController.java diff --git a/bugsnag-spring/src/jakartaTest/java/com/bugsnag/testapp/springboot/TestSpringBootApplication.java b/bugsnag-spring/src/test/java/com/bugsnag/testapp/springboot/TestSpringBootApplication.java similarity index 100% rename from bugsnag-spring/src/jakartaTest/java/com/bugsnag/testapp/springboot/TestSpringBootApplication.java rename to bugsnag-spring/src/test/java/com/bugsnag/testapp/springboot/TestSpringBootApplication.java diff --git a/bugsnag/build.gradle b/bugsnag/build.gradle deleted file mode 100644 index 140e8a75..00000000 --- a/bugsnag/build.gradle +++ /dev/null @@ -1,53 +0,0 @@ -plugins { - id "com.github.hierynomus.license" version "0.16.1" -} - -apply plugin: 'java-library' -apply from: '../common.gradle' - -compileJava { - sourceCompatibility = '1.7' - targetCompatibility = '1.7' -} - -compileTestJava { - sourceCompatibility = '1.7' - targetCompatibility = '1.7' -} - -repositories { - mavenCentral() -} - -dependencies { - api "com.fasterxml.jackson.core:jackson-databind:2.14.1" - api "org.slf4j:slf4j-api:${slf4jApiVersion}" - compileOnly "javax.servlet:javax.servlet-api:${javaxServletApiVersion}" - compileOnly "jakarta.servlet:jakarta.servlet-api:${jakartaServletApiVersion}" - compileOnly("ch.qos.logback:logback-classic:${logbackVersion}") { - exclude group: "org.slf4j" - } - - testImplementation "junit:junit:${junitVersion}" - testImplementation "org.slf4j:log4j-over-slf4j:${slf4jApiVersion}" - testImplementation "javax.servlet:javax.servlet-api:${javaxServletApiVersion}" - testImplementation "jakarta.servlet:jakarta.servlet-api:${jakartaServletApiVersion}" - testImplementation "org.mockito:mockito-core:${mockitoVersion}" - testImplementation("ch.qos.logback:logback-classic:${logbackVersion}") { - exclude group: "org.slf4j" - } -} - -// license checking -license { - header rootProject.file('LICENSE') - ignoreFailures true -} - -downloadLicenses { - dependencyConfiguration "compile" -} - -java { - withJavadocJar() -} \ No newline at end of file diff --git a/bugsnag/build.gradle.kts b/bugsnag/build.gradle.kts new file mode 100644 index 00000000..8b0845c4 --- /dev/null +++ b/bugsnag/build.gradle.kts @@ -0,0 +1,57 @@ +plugins { + alias(libs.plugins.license) + `java-library` +} + +apply(from = "../common.gradle.kts") + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +repositories { + mavenCentral() +} + +dependencies { + api(libs.jackson.databind) + api(libs.slf4j.api) + compileOnly(libs.jakarta.servlet.api) + compileOnly(libs.logback.classic) { + exclude(group = "org.slf4j") + } + + testImplementation(libs.junit) + testImplementation(libs.log4j.over.slf4j) + testImplementation(libs.jakarta.servlet.api) + testImplementation(libs.mockito.core) + testImplementation(libs.logback.classic) { + exclude(group = "org.slf4j") + } +} + +// license checking +configure { + header = rootProject.file("LICENSE") + isIgnoreFailures = true +} + +tasks.named("downloadLicenses") { + // Note: dependencyConfiguration property needs to be set through the plugin's DSL + // This may require checking the plugin documentation for Kotlin DSL syntax +} + +java { + withJavadocJar() +} + +/** ---- Publishing config ---- + * Pulls in publishing+signing rules from the shared release.gradle.kts. + * This will create tasks like: + * :bugsnag:publishMavenJavaPublicationToTestRepository + * :bugsnag:publishMavenJavaPublicationToOssrhStagingRepository + */ +apply(from = "${rootProject.projectDir}/release.gradle.kts") + diff --git a/bugsnag/src/main/java/com/bugsnag/Bugsnag.java b/bugsnag/src/main/java/com/bugsnag/Bugsnag.java index abfaffd0..635a0439 100644 --- a/bugsnag/src/main/java/com/bugsnag/Bugsnag.java +++ b/bugsnag/src/main/java/com/bugsnag/Bugsnag.java @@ -58,10 +58,10 @@ public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) { private Configuration config; private final SessionTracker sessionTracker; - private static final ThreadLocal THREAD_METADATA = new ThreadLocal() { + private static final ThreadLocal THREAD_METADATA = new ThreadLocal() { @Override - public MetaData initialValue() { - return new MetaData(); + public Metadata initialValue() { + return new Metadata(); } }; @@ -228,36 +228,40 @@ public void setEndpoint(String endpoint) { } /** - * Set which keys should be filtered when sending metaData to Bugsnag. + * Set which keys should be redacted when sending metadata to Bugsnag. * Use this when you want to ensure sensitive information, such as passwords - * or credit card information is stripped from metaData you send to Bugsnag. - * Any keys in metaData which contain these strings will be marked as - * [FILTERED] when send to Bugsnag. + * or credit card information is stripped from metadata you send to Bugsnag. + * Any keys in metadata which contain these strings will be marked as + * [REDACTED] when send to Bugsnag. * - * @param filters a list of String keys to filter from metaData + * @param redactedKeys a list of String keys to redact from metadata */ - public void setFilters(String... filters) { - config.filters = filters; + public void setRedactedKeys(String... redactedKeys) { + config.redactedKeys = redactedKeys; } /** * Set which exception classes should be ignored (not sent) by Bugsnag. * - * @param ignoreClasses a list of exception classes to ignore + * @param discardClasses a list of exception classes to ignore */ - public void setIgnoreClasses(String... ignoreClasses) { - config.ignoreClasses = ignoreClasses; + public void setDiscardClasses(String... discardClasses) { + config.discardClasses = discardClasses; } /** * Set for which releaseStages errors should be sent to Bugsnag. * Use this to stop errors from development builds being sent. * - * @param notifyReleaseStages a list of releaseStages to notify for + * @param enabledReleaseStages a list of releaseStages to notify for * @see #setReleaseStage */ - public void setNotifyReleaseStages(String... notifyReleaseStages) { - config.notifyReleaseStages = notifyReleaseStages; + public void setEnabledReleaseStages(String... enabledReleaseStages) { + if (enabledReleaseStages == null || enabledReleaseStages.length == 0) { + config.enabledReleaseStages = Collections.emptySet(); + } else { + config.enabledReleaseStages = Set.of(enabledReleaseStages); + } } /** @@ -289,7 +293,7 @@ public void setProxy(Proxy proxy) { * Set the current "release stage" of your application. * * @param releaseStage the release stage of the app - * @see #setNotifyReleaseStages + * @see #setEnabledReleaseStages */ public void setReleaseStage(String releaseStage) { config.releaseStage = releaseStage; @@ -302,14 +306,15 @@ public void setReleaseStage(String releaseStage) { * environment. * * @param sendThreads should we send thread state with error reports - * @see #setNotifyReleaseStages + * @see #setEnabledReleaseStages */ public void setSendThreads(boolean sendThreads) { config.sendThreads = sendThreads; } /** - * Set a timeout (in ms) to use when delivering Bugsnag error reports and sessions. + * Set a timeout (in ms) to use when delivering Bugsnag error reports and + * sessions. * This is a convenient shorthand for bugsnag.getDelivery().setTimeout(); * * @param timeout the timeout to set (in ms) @@ -435,14 +440,14 @@ public boolean notify(Report report, Callback reportCallback) { // Don't notify if this error class should be ignored if (config.shouldIgnoreClass(report.getExceptionName())) { - LOGGER.debug("Error not reported to Bugsnag - {} is in 'ignoreClasses'", + LOGGER.debug("Error not reported to Bugsnag - {} is in 'discardClasses'", report.getExceptionName()); return false; } - // Don't notify unless releaseStage is in notifyReleaseStages + // Don't notify unless releaseStage is in enabledReleaseStages if (!config.shouldNotifyForReleaseStage()) { - LOGGER.debug("Error not reported to Bugsnag - {} is not in 'notifyReleaseStages'", + LOGGER.debug("Error not reported to Bugsnag - {} is not in 'enabledReleaseStages'", config.releaseStage); return false; } @@ -465,7 +470,7 @@ public boolean notify(Report report, Callback reportCallback) { } // Add thread metadata to the report - report.mergeMetaData(THREAD_METADATA.get()); + report.mergeMetadata(THREAD_METADATA.get()); // Run the report-specific beforeNotify callback, if given if (reportCallback != null) { @@ -618,14 +623,14 @@ public void close() { * @param key the key of the metadata to add * @param value the metadata value to add */ - public static void addThreadMetaData(String tabName, String key, Object value) { + public static void addThreadMetadata(String tabName, String key, Object value) { THREAD_METADATA.get().addToTab(tabName, key, value); } /** * Clears all metadata added to the current thread */ - public static void clearThreadMetaData() { + public static void clearThreadMetadata() { THREAD_METADATA.get().clear(); } @@ -634,7 +639,7 @@ public static void clearThreadMetaData() { * * @param tabName the name of the tab to remove */ - public static void clearThreadMetaData(String tabName) { + public static void clearThreadMetadata(String tabName) { THREAD_METADATA.get().clearTab(tabName); } @@ -644,7 +649,7 @@ public static void clearThreadMetaData(String tabName) { * @param tabName the name of the tab to that the metadata is in * @param key the key of the metadata to remove */ - public static void clearThreadMetaData(String tabName, String key) { + public static void clearThreadMetadata(String tabName, String key) { THREAD_METADATA.get().clearKey(tabName, key); } diff --git a/bugsnag/src/main/java/com/bugsnag/BugsnagAppender.java b/bugsnag/src/main/java/com/bugsnag/BugsnagAppender.java index 5d3cd23d..c65df317 100644 --- a/bugsnag/src/main/java/com/bugsnag/BugsnagAppender.java +++ b/bugsnag/src/main/java/com/bugsnag/BugsnagAppender.java @@ -3,9 +3,9 @@ import com.bugsnag.callbacks.Callback; import com.bugsnag.delivery.Delivery; import com.bugsnag.logback.BugsnagMarker; -import com.bugsnag.logback.LogbackMetaData; -import com.bugsnag.logback.LogbackMetaDataKey; -import com.bugsnag.logback.LogbackMetaDataTab; +import com.bugsnag.logback.LogbackMetadata; +import com.bugsnag.logback.LogbackMetadataKey; +import com.bugsnag.logback.LogbackMetadataTab; import com.bugsnag.logback.ProxyConfiguration; import ch.qos.logback.classic.Level; @@ -48,14 +48,14 @@ public class BugsnagAppender extends UnsynchronizedAppenderBase { /** Bugsnag error server endpoint. */ private String endpoint; - /** Property names that should be filtered out before sending to Bugsnag servers. */ - private Set filteredProperties = new HashSet(); + /** Property names that should be redacted before sending to Bugsnag servers. */ + private Set redactedKeys = new HashSet(); /** Exception classes to be ignored. */ - private Set ignoredClasses = new HashSet(); + private Set discardClasses = new HashSet(); /** Release stages that should be notified. */ - private Set notifyReleaseStages = new HashSet(); + private Set enabledReleaseStages = new HashSet(); /** Project packages. */ private Set projectPackages = new HashSet(); @@ -75,7 +75,7 @@ public class BugsnagAppender extends UnsynchronizedAppenderBase { /** Application version. */ private String appVersion; - private List globalMetaData = new ArrayList(); + private List globalMetadata = new ArrayList(); /** Bugsnag client. */ private Bugsnag bugsnag = null; @@ -254,27 +254,27 @@ private Bugsnag createBugsnag() { bugsnag.setTimeout(timeout); } - if (filteredProperties.size() > 0) { - bugsnag.setFilters(filteredProperties.toArray(new String[0])); + if (!redactedKeys.isEmpty()) { + bugsnag.setRedactedKeys(redactedKeys.toArray(new String[0])); } - bugsnag.setIgnoreClasses(ignoredClasses.toArray(new String[0])); + bugsnag.setDiscardClasses(discardClasses.toArray(new String[0])); - if (notifyReleaseStages.size() > 0) { - bugsnag.setNotifyReleaseStages(notifyReleaseStages.toArray(new String[0])); + if (!enabledReleaseStages.isEmpty()) { + bugsnag.setEnabledReleaseStages(enabledReleaseStages.toArray(new String[0])); } bugsnag.setProjectPackages(projectPackages.toArray(new String[0])); bugsnag.setSendThreads(sendThreads); - // Add a callback to put global meta data on every report + // Add a callback to put global metadata on every report bugsnag.addCallback(new Callback() { @Override public void beforeNotify(Report report) { - for (LogbackMetaData metaData : globalMetaData) { - for (LogbackMetaDataTab tab : metaData.getTabs()) { - for (LogbackMetaDataKey key : tab.getKeys()) { + for (LogbackMetadata metadata : globalMetadata) { + for (LogbackMetadataTab tab : metadata.getTabs()) { + for (LogbackMetadataKey key : tab.getKeys()) { report.addToTab(tab.getName(), key.getName(), key.getValue()); @@ -374,68 +374,78 @@ public void setEndpoint(String endpoint) { } /** - * @see Bugsnag#setFilters(String...) + * @see Bugsnag#setRedactedKeys(String...) */ - public void setFilteredProperty(String filter) { - this.filteredProperties.add(filter); + public void setRedactedKey(String key) { + this.redactedKeys.add(key); if (bugsnag != null) { - bugsnag.setFilters(this.filteredProperties.toArray(new String[0])); + bugsnag.setRedactedKeys(this.redactedKeys.toArray(new String[0])); } } /** - * @see Bugsnag#setFilters(String...) + * @see Bugsnag#setRedactedKeys(String...) */ - public void setFilteredProperties(String filters) { - this.filteredProperties.addAll(split(filters)); + public void setRedactedKeys(String key) { + this.redactedKeys.addAll(split(key)); if (bugsnag != null) { - bugsnag.setFilters(this.filteredProperties.toArray(new String[0])); + bugsnag.setRedactedKeys(this.redactedKeys.toArray(new String[0])); } } + @Deprecated + public void setIgnoredClass(String ignoredClass) { + setDiscardClass(ignoredClass); + } + /** - * @see Bugsnag#setIgnoreClasses(String...) + * @see Bugsnag#setDiscardClasses(String...) */ - public void setIgnoredClass(String ignoredClass) { - this.ignoredClasses.add(ignoredClass); + public void setDiscardClass(String discardClass) { + this.discardClasses.add(discardClass); if (bugsnag != null) { - bugsnag.setIgnoreClasses(this.ignoredClasses.toArray(new String[0])); + bugsnag.setDiscardClasses(this.discardClasses.toArray(new String[0])); } } /** - * @see Bugsnag#setIgnoreClasses(String...) + * @see Bugsnag#setDiscardClasses(String...) */ - public void setIgnoredClasses(String ignoredClasses) { - this.ignoredClasses.addAll(split(ignoredClasses)); + public void setDiscardClasses(String discardClasses) { + this.discardClasses.addAll(split(discardClasses)); if (bugsnag != null) { - bugsnag.setIgnoreClasses(this.ignoredClasses.toArray(new String[0])); + bugsnag.setDiscardClasses(this.discardClasses.toArray(new String[0])); } } + @Deprecated + public void setNotifyReleaseStage(String notifyReleaseStage) { + setEnabledReleaseStage(notifyReleaseStage); + } + /** - * @see Bugsnag#setNotifyReleaseStages(String...) + * @see Bugsnag#setEnabledReleaseStages(String...) */ - public void setNotifyReleaseStage(String notifyReleaseStage) { - this.notifyReleaseStages.add(notifyReleaseStage); + public void setEnabledReleaseStage(String enabledReleaseStage) { + this.enabledReleaseStages.add(enabledReleaseStage); if (bugsnag != null) { - bugsnag.setNotifyReleaseStages(this.notifyReleaseStages.toArray(new String[0])); + bugsnag.setEnabledReleaseStages(this.enabledReleaseStages.toArray(new String[0])); } } /** - * @see Bugsnag#setNotifyReleaseStages(String...) + * @see Bugsnag#setEnabledReleaseStages(String...) */ - public void setNotifyReleaseStages(String notifyReleaseStages) { - this.notifyReleaseStages.addAll(split(notifyReleaseStages)); + public void setEnabledReleaseStages(String enabledReleaseStages) { + this.enabledReleaseStages.addAll(split(enabledReleaseStages)); if (bugsnag != null) { - bugsnag.setNotifyReleaseStages(this.notifyReleaseStages.toArray(new String[0])); + bugsnag.setEnabledReleaseStages(this.enabledReleaseStages.toArray(new String[0])); } } @@ -524,10 +534,15 @@ public void setAppVersion(String appVersion) { * Internal use only * Should only be used via the logback.xml file * - * @param metaData Adds meta data to every report + * @param metadata Adds metadata to every report */ - public void setMetaData(LogbackMetaData metaData) { - this.globalMetaData.add(metaData); + public void setMetadata(LogbackMetadata metadata) { + this.globalMetadata.add(metadata); + } + + @Deprecated + public void setMetaData(LogbackMetadata metadata) { + setMetadata(metadata); } /** diff --git a/bugsnag/src/main/java/com/bugsnag/Configuration.java b/bugsnag/src/main/java/com/bugsnag/Configuration.java index 351c1c0d..d7652574 100644 --- a/bugsnag/src/main/java/com/bugsnag/Configuration.java +++ b/bugsnag/src/main/java/com/bugsnag/Configuration.java @@ -4,7 +4,6 @@ import com.bugsnag.callbacks.Callback; import com.bugsnag.callbacks.DeviceCallback; import com.bugsnag.callbacks.JakartaServletCallback; -import com.bugsnag.callbacks.JavaxServletCallback; import com.bugsnag.delivery.AsyncHttpDelivery; import com.bugsnag.delivery.Delivery; import com.bugsnag.delivery.HttpDelivery; @@ -20,6 +19,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; @@ -37,9 +37,9 @@ public class Configuration { public Delivery delivery; public EndpointConfiguration endpointConfiguration; public Delivery sessionDelivery; - public String[] filters = new String[]{"password", "secret", "Authorization", "Cookie"}; - public String[] ignoreClasses; - public String[] notifyReleaseStages = null; + public String[] redactedKeys = new String[] {"password", "secret", "Authorization", "Cookie"}; + public String[] discardClasses; + public Set enabledReleaseStages = null; public String[] projectPackages; public String releaseStage; public boolean sendThreads = false; @@ -61,30 +61,24 @@ public class Configuration { this.delivery = new AsyncHttpDelivery(endpointConfiguration.getNotifyEndpoint()); this.sessionDelivery = new AsyncHttpDelivery(endpointConfiguration.getSessionEndpoint()); - if (JavaxServletCallback.isAvailable()) { - addCallback(new JavaxServletCallback()); - } - if (JakartaServletCallback.isAvailable()) { addCallback(new JakartaServletCallback()); } } boolean shouldNotifyForReleaseStage() { - if (notifyReleaseStages == null) { + if (enabledReleaseStages == null) { return true; } - - List stages = Arrays.asList(notifyReleaseStages); - return stages.contains(releaseStage); + return enabledReleaseStages.contains(releaseStage); } boolean shouldIgnoreClass(String className) { - if (ignoreClasses == null) { + if (discardClasses == null) { return false; } - List classes = Arrays.asList(ignoreClasses); + List classes = Arrays.asList(discardClasses); return classes.contains(className); } diff --git a/bugsnag/src/main/java/com/bugsnag/Diagnostics.java b/bugsnag/src/main/java/com/bugsnag/Diagnostics.java index d6aa3e1a..671e3fed 100644 --- a/bugsnag/src/main/java/com/bugsnag/Diagnostics.java +++ b/bugsnag/src/main/java/com/bugsnag/Diagnostics.java @@ -11,7 +11,7 @@ class Diagnostics { Map app; Map device; Map user = new HashMap(); - MetaData metaData = new MetaData(); + Metadata metadata = new Metadata(); Diagnostics(Configuration configuration) { app = getDefaultAppInfo(configuration); diff --git a/bugsnag/src/main/java/com/bugsnag/MetaData.java b/bugsnag/src/main/java/com/bugsnag/Metadata.java similarity index 80% rename from bugsnag/src/main/java/com/bugsnag/MetaData.java rename to bugsnag/src/main/java/com/bugsnag/Metadata.java index 33d215fd..92fd4ea6 100644 --- a/bugsnag/src/main/java/com/bugsnag/MetaData.java +++ b/bugsnag/src/main/java/com/bugsnag/Metadata.java @@ -3,7 +3,7 @@ import java.util.HashMap; import java.util.Map; -class MetaData extends HashMap { +class Metadata extends HashMap { private static final long serialVersionUID = 2530038179702722770L; public void addToTab(String tabName, String key, Object value) { @@ -20,9 +20,9 @@ void clearKey(String tabName, String key) { tab.remove(key); } - void merge(MetaData metaData) { - for (String tabName : metaData.keySet()) { - getTab(tabName).putAll(metaData.getTab(tabName)); + void merge(Metadata metadata) { + for (String tabName : metadata.keySet()) { + getTab(tabName).putAll(metadata.getTab(tabName)); } } diff --git a/bugsnag/src/main/java/com/bugsnag/util/FilteredMap.java b/bugsnag/src/main/java/com/bugsnag/RedactedMap.java similarity index 55% rename from bugsnag/src/main/java/com/bugsnag/util/FilteredMap.java rename to bugsnag/src/main/java/com/bugsnag/RedactedMap.java index 1adc9269..b417137d 100644 --- a/bugsnag/src/main/java/com/bugsnag/util/FilteredMap.java +++ b/bugsnag/src/main/java/com/bugsnag/RedactedMap.java @@ -1,24 +1,24 @@ -package com.bugsnag.util; +package com.bugsnag; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; /** - * Decorates a map by replacing values of filtered keys. + * Decorates a map by replacing values of redacted keys. */ -public class FilteredMap implements Map { +class RedactedMap implements Map { - private static final String FILTERED_PLACEHOLDER = "[FILTERED]"; + private static final String REDACTED_PLACEHOLDER = "[REDACTED]"; - private final Map filteredCopy; - private final Collection keyFilters = new ArrayList(); + private final Map redactedCopy; + private final Collection redactedKeys = new HashSet<>(); - public FilteredMap(Map map, Collection keyFilters) { - this.keyFilters.addAll(keyFilters); - this.filteredCopy = createCopy(map); + RedactedMap(Map map, Collection redactedKeys) { + this.redactedKeys.addAll(redactedKeys); + this.redactedCopy = createCopy(map); } private Map createCopy(Map map) { @@ -36,84 +36,87 @@ private Map createCopy(Map map) { @Override public int size() { - return filteredCopy.size(); + return redactedCopy.size(); } @Override public boolean isEmpty() { - return filteredCopy.isEmpty(); + return redactedCopy.isEmpty(); } @Override public boolean containsKey(Object key) { - return filteredCopy.containsKey(key); + return redactedCopy.containsKey(key); } @Override public boolean containsValue(Object value) { - return filteredCopy.containsValue(value); + return redactedCopy.containsValue(value); } @Override public Object get(Object key) { - return filteredCopy.get(key); + return redactedCopy.get(key); } @Override public Object put(String key, Object value) { if (value == null) { - return filteredCopy.put(key, null); + return redactedCopy.put(key, null); } Object transformedValue = transformEntry(key, value); - return filteredCopy.put(key, transformedValue); + return redactedCopy.put(key, transformedValue); } @Override public Object remove(Object key) { - return filteredCopy.remove(key); + return redactedCopy.remove(key); } @Override public void putAll(Map mapValues) { Map copy = createCopy(mapValues); - filteredCopy.putAll(copy); + redactedCopy.putAll(copy); } @Override public void clear() { - filteredCopy.clear(); + redactedCopy.clear(); } @Override public Set keySet() { - return filteredCopy.keySet(); + return redactedCopy.keySet(); } @Override public Collection values() { - return filteredCopy.values(); + return redactedCopy.values(); } @Override public Set> entrySet() { - return filteredCopy.entrySet(); + return redactedCopy.entrySet(); } @SuppressWarnings("unchecked") private Object transformEntry(Object key, Object value) { if (value instanceof Map) { - return new FilteredMap((Map) value, keyFilters); + return new RedactedMap((Map) value, redactedKeys); } - return shouldFilterKey((String) key) ? FILTERED_PLACEHOLDER : value; + return shouldRedactKey((String) key) ? REDACTED_PLACEHOLDER : value; } - private boolean shouldFilterKey(String key) { - if (keyFilters == null || key == null) { + private boolean shouldRedactKey(String key) { + if (key == null) { return false; } - - for (String filter : keyFilters) { - if (key.contains(filter)) { + // Check for common keys first before looping through all + if (redactedKeys.contains(key)) { + return true; + } + for (String redactedKey : redactedKeys) { + if (key.contains(redactedKey)) { return true; } } diff --git a/bugsnag/src/main/java/com/bugsnag/Report.java b/bugsnag/src/main/java/com/bugsnag/Report.java index dd1527e5..5f963baf 100644 --- a/bugsnag/src/main/java/com/bugsnag/Report.java +++ b/bugsnag/src/main/java/com/bugsnag/Report.java @@ -2,13 +2,13 @@ import com.bugsnag.serialization.Expose; -import com.bugsnag.util.FilteredMap; +import com.fasterxml.jackson.annotation.JsonProperty; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; public class Report { @@ -125,8 +125,9 @@ public Map getUser() { } @Expose - public Map getMetaData() { - return new FilteredMap(diagnostics.metaData, Arrays.asList(config.filters)); + @JsonProperty("metaData") + public Map getMetadata() { + return new RedactedMap(diagnostics.metadata, Set.of(config.redactedKeys)); } @Expose @@ -188,7 +189,7 @@ public String getExceptionMessage() { * @return the modified report */ public Report addToTab(String tabName, String key, Object value) { - diagnostics.metaData.addToTab(tabName, key, value); + diagnostics.metadata.addToTab(tabName, key, value); return this; } @@ -199,7 +200,7 @@ public Report addToTab(String tabName, String key, Object value) { * @return The message from the exception contained in this error report. */ public Report clearTab(String tabName) { - diagnostics.metaData.clearTab(tabName); + diagnostics.metadata.clearTab(tabName); return this; } @@ -333,8 +334,8 @@ void setHandledState(HandledState handledState) { this.handledState = handledState; } - void mergeMetaData(MetaData metaData) { - diagnostics.metaData.merge(metaData); + void mergeMetadata(Metadata metadata) { + diagnostics.metadata.merge(metadata); } static class SeverityReason { diff --git a/bugsnag/src/main/java/com/bugsnag/callbacks/JakartaServletCallback.java b/bugsnag/src/main/java/com/bugsnag/callbacks/JakartaServletCallback.java index 3945f48e..17c4f67c 100644 --- a/bugsnag/src/main/java/com/bugsnag/callbacks/JakartaServletCallback.java +++ b/bugsnag/src/main/java/com/bugsnag/callbacks/JakartaServletCallback.java @@ -33,7 +33,7 @@ public void beforeNotify(Report report) { return; } - // Add request information to metaData + // Add request information to metadata report .addToTab("request", "url", request.getRequestURL().toString()) .addToTab("request", "method", request.getMethod()) diff --git a/bugsnag/src/main/java/com/bugsnag/callbacks/JavaxServletCallback.java b/bugsnag/src/main/java/com/bugsnag/callbacks/JavaxServletCallback.java deleted file mode 100644 index 233fc7ba..00000000 --- a/bugsnag/src/main/java/com/bugsnag/callbacks/JavaxServletCallback.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.bugsnag.callbacks; - -import com.bugsnag.Report; -import com.bugsnag.servlet.BugsnagServletRequestListener; - -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import javax.servlet.http.HttpServletRequest; - -public class JavaxServletCallback implements Callback { - private static final String HEADER_X_FORWARDED_FOR = "X-FORWARDED-FOR"; - - /** - * @return true if the servlet request listener is available. - */ - public static boolean isAvailable() { - try { - Class.forName("javax.servlet.ServletRequestListener", false, - JavaxServletCallback.class.getClassLoader()); - return true; - } catch (ClassNotFoundException ex) { - return false; - } - } - - @Override - public void beforeNotify(Report report) { - // Check if we have any servlet request data available - HttpServletRequest request = BugsnagServletRequestListener.getServletRequest(); - if (request == null) { - return; - } - - // Add request information to metaData - report - .addToTab("request", "url", request.getRequestURL().toString()) - .addToTab("request", "method", request.getMethod()) - .addToTab("request", "params", - new HashMap(request.getParameterMap())) - .addToTab("request", "clientIp", getClientIp(request)) - .addToTab("request", "headers", getHeaderMap(request)); - - // Set default context - if (report.getContext() == null) { - report.setContext(request.getMethod() + " " + request.getRequestURI()); - } - } - - private String getClientIp(HttpServletRequest request) { - String remoteAddr = request.getRemoteAddr(); - String forwardedAddr = request.getHeader(HEADER_X_FORWARDED_FOR); - if (forwardedAddr != null) { - remoteAddr = forwardedAddr; - int idx = remoteAddr.indexOf(','); - if (idx > -1) { - remoteAddr = remoteAddr.substring(0, idx); - } - } - return remoteAddr; - } - - private Map getHeaderMap(HttpServletRequest request) { - Map headers = new HashMap(); - Enumeration headerNames = request.getHeaderNames(); - - while (headerNames != null && headerNames.hasMoreElements()) { - String key = headerNames.nextElement(); - Enumeration headerValues = request.getHeaders(key); - StringBuilder value = new StringBuilder(); - - if (headerValues != null && headerValues.hasMoreElements()) { - value.append(headerValues.nextElement()); - - // If there are multiple values for the header, do comma-separated concat - // as per RFC 2616: - // https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 - while (headerValues.hasMoreElements()) { - value.append(",").append(headerValues.nextElement()); - } - } - - headers.put(key, value.toString()); - } - - return headers; - } -} diff --git a/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetaData.java b/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetaData.java deleted file mode 100644 index d600811a..00000000 --- a/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetaData.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bugsnag.logback; - -import java.util.ArrayList; -import java.util.List; - -/** Used to allow meta data to be added in the logback.xml file */ -public class LogbackMetaData { - - private List tabs = new ArrayList(); - - /** - * @return The tabs in the meta data - */ - public List getTabs() { - return tabs; - } - - /** - * @param tab a new tab to add to the meta data - */ - public void setTab(LogbackMetaDataTab tab) { - this.tabs.add(tab); - } -} diff --git a/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetadata.java b/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetadata.java new file mode 100644 index 00000000..b02394a3 --- /dev/null +++ b/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetadata.java @@ -0,0 +1,24 @@ +package com.bugsnag.logback; + +import java.util.ArrayList; +import java.util.List; + +/** Used to allow metadata to be added in the logback.xml file */ +public class LogbackMetadata { + + private List tabs = new ArrayList(); + + /** + * @return The tabs in the metadata + */ + public List getTabs() { + return tabs; + } + + /** + * @param tab a new tab to add to the metadata + */ + public void setTab(LogbackMetadataTab tab) { + this.tabs.add(tab); + } +} diff --git a/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetaDataKey.java b/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetadataKey.java similarity index 84% rename from bugsnag/src/main/java/com/bugsnag/logback/LogbackMetaDataKey.java rename to bugsnag/src/main/java/com/bugsnag/logback/LogbackMetadataKey.java index 77732c45..eee1301a 100644 --- a/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetaDataKey.java +++ b/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetadataKey.java @@ -1,7 +1,7 @@ package com.bugsnag.logback; -/** Used to allow meta data to be added in the logback.xml file */ -public class LogbackMetaDataKey { +/** Used to allow metadata to be added in the logback.xml file */ +public class LogbackMetadataKey { private String name; diff --git a/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetaDataTab.java b/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetadataTab.java similarity index 65% rename from bugsnag/src/main/java/com/bugsnag/logback/LogbackMetaDataTab.java rename to bugsnag/src/main/java/com/bugsnag/logback/LogbackMetadataTab.java index 048b240b..24954caf 100644 --- a/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetaDataTab.java +++ b/bugsnag/src/main/java/com/bugsnag/logback/LogbackMetadataTab.java @@ -3,12 +3,12 @@ import java.util.ArrayList; import java.util.List; -/** Used to allow meta data to be added in the logback.xml file */ -public class LogbackMetaDataTab { +/** Used to allow metadata to be added in the logback.xml file */ +public class LogbackMetadataTab { private String name; - private List keys = new ArrayList(); + private List keys = new ArrayList(); /** * @return The name of the tab @@ -27,14 +27,14 @@ public void setName(String name) { /** * @return The keys in the tab */ - public List getKeys() { + public List getKeys() { return keys; } /** * @param key A key to add to the tab */ - public void setKey(LogbackMetaDataKey key) { + public void setKey(LogbackMetadataKey key) { this.keys.add(key); } } diff --git a/bugsnag/src/main/java/com/bugsnag/servlet/BugsnagServletContainerInitializer.java b/bugsnag/src/main/java/com/bugsnag/servlet/BugsnagServletContainerInitializer.java deleted file mode 100644 index a6c498cf..00000000 --- a/bugsnag/src/main/java/com/bugsnag/servlet/BugsnagServletContainerInitializer.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.bugsnag.servlet; - -/** - * @see com.bugsnag.servlet.javax.BugsnagServletContainerInitializer - * @deprecated since 3.7.1 - to be replaced with {@code com.bugsnag.servlet.javax.BugsnagServletContainerInitializer} - */ -@Deprecated -public class BugsnagServletContainerInitializer extends com.bugsnag.servlet.javax.BugsnagServletContainerInitializer { -} diff --git a/bugsnag/src/main/java/com/bugsnag/servlet/BugsnagServletRequestListener.java b/bugsnag/src/main/java/com/bugsnag/servlet/BugsnagServletRequestListener.java deleted file mode 100644 index d10155c1..00000000 --- a/bugsnag/src/main/java/com/bugsnag/servlet/BugsnagServletRequestListener.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.bugsnag.servlet; - -/** - * @see com.bugsnag.servlet.javax.BugsnagServletRequestListener - * @deprecated since 3.7.1 - to be replaced with {@code com.bugsnag.servlet.javax.BugsnagServletRequestListener} - */ -@Deprecated -public class BugsnagServletRequestListener extends com.bugsnag.servlet.javax.BugsnagServletRequestListener { -} diff --git a/bugsnag/src/main/java/com/bugsnag/servlet/jakarta/BugsnagServletRequestListener.java b/bugsnag/src/main/java/com/bugsnag/servlet/jakarta/BugsnagServletRequestListener.java index 1867078f..3455bc54 100644 --- a/bugsnag/src/main/java/com/bugsnag/servlet/jakarta/BugsnagServletRequestListener.java +++ b/bugsnag/src/main/java/com/bugsnag/servlet/jakarta/BugsnagServletRequestListener.java @@ -29,7 +29,7 @@ public void requestInitialized(ServletRequestEvent servletRequestEvent) { @Override public void requestDestroyed(ServletRequestEvent servletRequestEvent) { SERVLET_REQUEST.remove(); - Bugsnag.clearThreadMetaData(); + Bugsnag.clearThreadMetadata(); } private void trackServletSession() { diff --git a/bugsnag/src/main/java/com/bugsnag/servlet/javax/BugsnagServletContainerInitializer.java b/bugsnag/src/main/java/com/bugsnag/servlet/javax/BugsnagServletContainerInitializer.java deleted file mode 100644 index af177c35..00000000 --- a/bugsnag/src/main/java/com/bugsnag/servlet/javax/BugsnagServletContainerInitializer.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.bugsnag.servlet.javax; - -import java.util.Set; -import javax.servlet.ServletContainerInitializer; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; - -public class BugsnagServletContainerInitializer implements ServletContainerInitializer { - @Override - public void onStartup(Set> cls, ServletContext context) throws ServletException { - context.addListener(BugsnagServletRequestListener.class); - } -} diff --git a/bugsnag/src/main/java/com/bugsnag/servlet/javax/BugsnagServletRequestListener.java b/bugsnag/src/main/java/com/bugsnag/servlet/javax/BugsnagServletRequestListener.java deleted file mode 100644 index a3e9e47a..00000000 --- a/bugsnag/src/main/java/com/bugsnag/servlet/javax/BugsnagServletRequestListener.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.bugsnag.servlet.javax; - -import com.bugsnag.Bugsnag; - -import javax.servlet.ServletRequest; -import javax.servlet.ServletRequestEvent; -import javax.servlet.ServletRequestListener; -import javax.servlet.http.HttpServletRequest; - -public class BugsnagServletRequestListener implements ServletRequestListener { - - private static final ThreadLocal SERVLET_REQUEST = - new ThreadLocal(); - - public static HttpServletRequest getServletRequest() { - return SERVLET_REQUEST.get(); - } - - @Override - public void requestInitialized(ServletRequestEvent servletRequestEvent) { - trackServletSession(); - ServletRequest servletRequest = servletRequestEvent.getServletRequest(); - - if (servletRequest instanceof HttpServletRequest) { - SERVLET_REQUEST.set((HttpServletRequest) servletRequest); - } - } - - @Override - public void requestDestroyed(ServletRequestEvent servletRequestEvent) { - SERVLET_REQUEST.remove(); - Bugsnag.clearThreadMetaData(); - } - - private void trackServletSession() { - for (Bugsnag bugsnag : Bugsnag.uncaughtExceptionClients()) { - if (bugsnag.shouldAutoCaptureSessions()) { - bugsnag.startSession(); - } - } - } -} diff --git a/bugsnag/src/test/java/com/bugsnag/AppenderMetaDataTest.java b/bugsnag/src/test/java/com/bugsnag/AppenderMetadataTest.java similarity index 67% rename from bugsnag/src/test/java/com/bugsnag/AppenderMetaDataTest.java rename to bugsnag/src/test/java/com/bugsnag/AppenderMetadataTest.java index c756ee1f..4ba4dc0a 100644 --- a/bugsnag/src/test/java/com/bugsnag/AppenderMetaDataTest.java +++ b/bugsnag/src/test/java/com/bugsnag/AppenderMetadataTest.java @@ -21,11 +21,11 @@ import java.util.Map; /** - * Test for using meta data via the Bugsnag Appender + * Test for using metadata via the Bugsnag Appender */ -public class AppenderMetaDataTest { +public class AppenderMetadataTest { - private static final Logger LOGGER = LoggerFactory.getLogger(AppenderMetaDataTest.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AppenderMetadataTest.class); private StubNotificationDelivery delivery; private Delivery originalDelivery; private BugsnagAppender appender; @@ -56,15 +56,15 @@ public void revertDelivery() { } @Test - public void testMetaDataFromLogbackFile() { + public void testMetadataFromLogbackFile() { // Send a log message LOGGER.warn("Test exception", new RuntimeException("test")); // Get the notification details Notification notification = delivery.getNotifications().get(0); - assertTrue(notification.getEvents().get(0).getMetaData().containsKey("logbackTab")); - Map myTab = getMetaDataMap(notification, "logbackTab"); + assertTrue(notification.getEvents().get(0).getMetadata().containsKey("logbackTab")); + Map myTab = getMetadataMap(notification, "logbackTab"); assertEquals("logbackValue1", myTab.get("logbackKey1")); assertEquals("logbackValue2", myTab.get("logbackKey2")); @@ -72,27 +72,27 @@ public void testMetaDataFromLogbackFile() { @Test @SuppressWarnings (value = "unchecked") - public void testMetaDataTypes() { + public void testMetadataTypes() { - Bugsnag.addThreadMetaData("myTab", "string key", "string value"); - Bugsnag.addThreadMetaData("myTab", "bool key", true); - Bugsnag.addThreadMetaData("myTab", "int key", 1); - Bugsnag.addThreadMetaData("myTab", "float key", 1.1); + Bugsnag.addThreadMetadata("myTab", "string key", "string value"); + Bugsnag.addThreadMetadata("myTab", "bool key", true); + Bugsnag.addThreadMetadata("myTab", "int key", 1); + Bugsnag.addThreadMetadata("myTab", "float key", 1.1); Map map = new HashMap(); map.put("key", "value"); - Bugsnag.addThreadMetaData("myTab", "object key", map); + Bugsnag.addThreadMetadata("myTab", "object key", map); Integer[] array = new Integer[] {1, 2, 3, 4, 5}; - Bugsnag.addThreadMetaData("myTab", "array key", array); + Bugsnag.addThreadMetadata("myTab", "array key", array); // Send a log message LOGGER.warn("Test exception", new RuntimeException("test")); // Get the notification details Notification notification = delivery.getNotifications().get(0); - assertTrue(notification.getEvents().get(0).getMetaData().containsKey("myTab")); - Map myTab = getMetaDataMap(notification, "myTab"); + assertTrue(notification.getEvents().get(0).getMetadata().containsKey("myTab")); + Map myTab = getMetadataMap(notification, "myTab"); assertEquals("string value", myTab.get("string key")); assertEquals(true, myTab.get("bool key")); @@ -103,12 +103,12 @@ public void testMetaDataTypes() { } @Test - public void testMetaDataRemoval() { + public void testMetadataRemoval() { - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "some key", "some thread value"); + // Add some thread metadata + Bugsnag.addThreadMetadata("thread", "some key", "some thread value"); - // Send three test logs, the first one with report meta data added + // Send three test logs, the first one with report metadata added LOGGER.warn(new BugsnagMarker(new Callback() { @Override public void beforeNotify(Report report) { @@ -118,39 +118,39 @@ public void beforeNotify(Report report) { LOGGER.warn("Test exception", new RuntimeException("test")); - Bugsnag.clearThreadMetaData(); + Bugsnag.clearThreadMetadata(); LOGGER.warn("Test exception", new RuntimeException("test")); // Check that three reports were sent to Bugsnag assertEquals(3, delivery.getNotifications().size()); - // Check the meta data is set as expected - // Should have both report and thread meta data + // Check the metadata is set as expected + // Should have both report and thread metadata Notification notification = delivery.getNotifications().get(0); Report report = notification.getEvents().get(0); - assertTrue(report.getMetaData().containsKey("report")); - assertTrue(report.getMetaData().containsKey("thread")); - assertEquals("some report value", getMetaDataMap(notification, "report").get("some key")); - assertEquals("some thread value", getMetaDataMap(notification, "thread").get("some key")); + assertTrue(report.getMetadata().containsKey("report")); + assertTrue(report.getMetadata().containsKey("thread")); + assertEquals("some report value", getMetadataMap(notification, "report").get("some key")); + assertEquals("some thread value", getMetadataMap(notification, "thread").get("some key")); - // Should have just thread meta data + // Should have just thread metadata notification = delivery.getNotifications().get(1); report = notification.getEvents().get(0); - assertFalse(report.getMetaData().containsKey("report")); - assertTrue(report.getMetaData().containsKey("thread")); - assertEquals("some thread value", getMetaDataMap(notification, "thread").get("some key")); + assertFalse(report.getMetadata().containsKey("report")); + assertTrue(report.getMetadata().containsKey("thread")); + assertEquals("some thread value", getMetadataMap(notification, "thread").get("some key")); - // Should have neither meta data + // Should have neither metadata notification = delivery.getNotifications().get(2); report = notification.getEvents().get(0); - assertFalse(report.getMetaData().containsKey("report")); - assertFalse(report.getMetaData().containsKey("thread")); + assertFalse(report.getMetadata().containsKey("report")); + assertFalse(report.getMetadata().containsKey("thread")); } @Test @SuppressWarnings (value = "unchecked") - public void testMetaDataFromMdc() { + public void testMetadataFromMdc() { MDC.put("context key1", "context value1"); MDC.put("context key2", "context value2"); @@ -160,22 +160,22 @@ public void testMetaDataFromMdc() { // Get the notification details Notification notification = delivery.getNotifications().get(0); - assertTrue(notification.getEvents().get(0).getMetaData().containsKey("Context")); - Map myTab = getMetaDataMap(notification, "Context"); + assertTrue(notification.getEvents().get(0).getMetadata().containsKey("Context")); + Map myTab = getMetadataMap(notification, "Context"); assertEquals("context value1", myTab.get("context key1")); assertEquals("context value2", myTab.get("context key2")); } /** - * Gets a hashmap key from the meta data in a notification + * Gets a hashmap key from the metadata in a notification * * @param notification The notification * @param key The key to get * @return The hash map */ @SuppressWarnings (value = "unchecked") - private Map getMetaDataMap(Notification notification, String key) { - return ((Map) notification.getEvents().get(0).getMetaData().get(key)); + private Map getMetadataMap(Notification notification, String key) { + return ((Map) notification.getEvents().get(0).getMetadata().get(key)); } } diff --git a/bugsnag/src/test/java/com/bugsnag/AppenderTest.java b/bugsnag/src/test/java/com/bugsnag/AppenderTest.java index 19c9ad42..248e50e1 100644 --- a/bugsnag/src/test/java/com/bugsnag/AppenderTest.java +++ b/bugsnag/src/test/java/com/bugsnag/AppenderTest.java @@ -87,7 +87,7 @@ public void testSimpleException() { assertEquals("test", notification.getEvents().get(0).getExceptionMessage()); assertEquals(Severity.WARNING.getValue(), notification.getEvents().get(0).getSeverity()); assertEquals("Test exception", - getMetaDataMap(notification, "Log event data").get("Message")); + getMetadataMap(notification, "Log event data").get("Message")); } @Test @@ -109,7 +109,7 @@ public void testFormattedMessage() { assertEquals("test", notification.getEvents().get(0).getExceptionMessage()); assertEquals(Severity.WARNING.getValue(), notification.getEvents().get(0).getSeverity()); assertEquals("Test exception, errorCode: " + value, - getMetaDataMap(notification, "Log event data").get("Message")); + getMetadataMap(notification, "Log event data").get("Message")); } @Test @@ -144,26 +144,22 @@ public void testBugsnagConfig() { assertEquals("gradleTask", config.appType); assertFalse(config.shouldAutoCaptureSessions()); - assertEquals(2, config.filters.length); - ArrayList filters = new ArrayList(Arrays.asList(config.filters)); - assertTrue(filters.contains("password")); - assertTrue(filters.contains("credit_card_number")); + assertEquals(2, config.redactedKeys.length); + ArrayList redactedKeys = new ArrayList(Arrays.asList(config.redactedKeys)); + assertTrue(redactedKeys.contains("password")); + assertTrue(redactedKeys.contains("credit_card_number")); - assertEquals(2, config.ignoreClasses.length); - ArrayList ignoreClasses - = new ArrayList(Arrays.asList(config.ignoreClasses)); - assertTrue(ignoreClasses.contains("com.example.Custom")); - assertTrue(ignoreClasses.contains("java.io.IOException")); + assertEquals(2, config.discardClasses.length); + ArrayList discardClasses = new ArrayList(Arrays.asList(config.discardClasses)); + assertTrue(discardClasses.contains("com.example.Custom")); + assertTrue(discardClasses.contains("java.io.IOException")); - assertEquals(2, config.notifyReleaseStages.length); - ArrayList notifyReleaseStages - = new ArrayList(Arrays.asList(config.notifyReleaseStages)); - assertTrue(notifyReleaseStages.contains("development")); - assertTrue(notifyReleaseStages.contains("test")); + assertEquals(2, config.enabledReleaseStages.size()); + assertTrue(config.enabledReleaseStages.contains("development")); + assertTrue(config.enabledReleaseStages.contains("test")); assertEquals(2, config.projectPackages.length); - ArrayList projectPackages - = new ArrayList(Arrays.asList(config.projectPackages)); + ArrayList projectPackages = new ArrayList(Arrays.asList(config.projectPackages)); assertTrue(projectPackages.contains("com.company.package2")); assertTrue(projectPackages.contains("com.company.package1")); @@ -208,7 +204,7 @@ public void testIgnoreClasses() { } @Test - public void testNotifyReleaseStages() { + public void testEnabledReleaseStages() { // Send a log with the release stage set to an excluded one appender.setReleaseStage("ignoredReleaseStage"); LOGGER.warn("Release stage ignored", new RuntimeException("test")); @@ -274,26 +270,26 @@ public void testAppType() { } @Test - public void testFilters() { + public void testRedactedKeys() { - // Add some meta data which should be filtered by key name - Bugsnag.addThreadMetaData("myTab", "password", "password value"); - Bugsnag.addThreadMetaData("myTab", "credit_card_number", "card number"); - Bugsnag.addThreadMetaData("myTab", "mysecret", "not filtered"); + // Add some metadata which should be redacted by key name + Bugsnag.addThreadMetadata("myTab", "password", "password value"); + Bugsnag.addThreadMetadata("myTab", "credit_card_number", "card number"); + Bugsnag.addThreadMetadata("myTab", "mysecret", "not redacted"); // Send a log message - LOGGER.warn("Exception with filtered meta data", new RuntimeException("test")); + LOGGER.warn("Exception with redacted metadata", new RuntimeException("test")); // Check that a report was sent to Bugsnag assertEquals(1, delivery.getNotifications().size()); Notification notification = delivery.getNotifications().get(0); - assertTrue(notification.getEvents().get(0).getMetaData().containsKey("myTab")); - Map myTab = getMetaDataMap(notification, "myTab"); + assertTrue(notification.getEvents().get(0).getMetadata().containsKey("myTab")); + Map myTab = getMetadataMap(notification, "myTab"); - assertEquals("[FILTERED]", myTab.get("password")); - assertEquals("[FILTERED]", myTab.get("credit_card_number")); - assertEquals("not filtered", myTab.get("mysecret")); + assertEquals("[REDACTED]", myTab.get("password")); + assertEquals("[REDACTED]", myTab.get("credit_card_number")); + assertEquals("not redacted", myTab.get("mysecret")); } @Test @@ -316,7 +312,7 @@ public void beforeNotify(Report report) { }); // Send a log message - LOGGER.warn("Exception with filtered meta data", new RuntimeException("test")); + LOGGER.warn("Exception with redacted meta data", new RuntimeException("test")); // Check that a report was sent to Bugsnag assertEquals(1, delivery.getNotifications().size()); @@ -412,14 +408,14 @@ private SessionTracker getSessionTracker(Bugsnag bugsnag) { } /** - * Gets a hashmap key from the meta data in a notification + * Gets a hashmap key from the metadata in a notification * * @param notification The notification * @param key The key to get * @return The hash map */ @SuppressWarnings (value = "unchecked") - private Map getMetaDataMap(Notification notification, String key) { - return ((Map) notification.getEvents().get(0).getMetaData().get(key)); + private Map getMetadataMap(Notification notification, String key) { + return ((Map) notification.getEvents().get(0).getMetadata().get(key)); } } diff --git a/bugsnag/src/test/java/com/bugsnag/BugsnagTest.java b/bugsnag/src/test/java/com/bugsnag/BugsnagTest.java index a0308425..e075be43 100644 --- a/bugsnag/src/test/java/com/bugsnag/BugsnagTest.java +++ b/bugsnag/src/test/java/com/bugsnag/BugsnagTest.java @@ -17,13 +17,14 @@ import org.junit.Test; import java.io.ByteArrayOutputStream; + import java.net.InetSocketAddress; import java.net.Proxy; + import java.util.HashMap; import java.util.Map; import java.util.Set; - public class BugsnagTest { private Bugsnag bugsnag; @@ -57,41 +58,41 @@ public void testIgnoreClasses() { bugsnag.setDelivery(BugsnagTestUtils.generateDelivery()); // Ignore neither - bugsnag.setIgnoreClasses(); + bugsnag.setDiscardClasses(); assertTrue(bugsnag.notify(new RuntimeException())); assertTrue(bugsnag.notify(new TestException())); // Ignore just RuntimeException - bugsnag.setIgnoreClasses(RuntimeException.class.getName()); + bugsnag.setDiscardClasses(RuntimeException.class.getName()); assertFalse(bugsnag.notify(new RuntimeException())); assertTrue(bugsnag.notify(new TestException())); // Ignore both - bugsnag.setIgnoreClasses(RuntimeException.class.getName(), TestException.class.getName()); + bugsnag.setDiscardClasses(RuntimeException.class.getName(), TestException.class.getName()); assertFalse(bugsnag.notify(new RuntimeException())); assertFalse(bugsnag.notify(new TestException())); } @Test - public void testNotifyReleaseStages() { + public void testEnabledReleaseStages() { bugsnag.setDelivery(BugsnagTestUtils.generateDelivery()); bugsnag.setReleaseStage("production"); // Never send - bugsnag.setNotifyReleaseStages(); + bugsnag.setEnabledReleaseStages(); assertFalse(bugsnag.notify(new Throwable())); // Ignore 'production' - bugsnag.setNotifyReleaseStages("staging", "development"); + bugsnag.setEnabledReleaseStages("staging"); assertFalse(bugsnag.notify(new Throwable())); // Allow 'production' - bugsnag.setNotifyReleaseStages("production"); + bugsnag.setEnabledReleaseStages("production"); assertTrue(bugsnag.notify(new Throwable())); // Allow 'production' and others - bugsnag.setNotifyReleaseStages("production", "staging", "development"); + bugsnag.setEnabledReleaseStages("production"); assertTrue(bugsnag.notify(new Throwable())); } @@ -164,21 +165,21 @@ public void close() { } @Test - public void testFilters() { - bugsnag.setFilters("testfilter1", "testfilter2"); + public void testRedactedKeys() { + bugsnag.setRedactedKeys("testredact1", "testredact2"); bugsnag.setDelivery(new Delivery() { @SuppressWarnings("unchecked") @Override public void deliver(Serializer serializer, Object object, Map headers) { Report report = ((Notification) object).getEvents().get(0); Map firstTab = - (Map) report.getMetaData().get("firsttab"); + (Map) report.getMetadata().get("firsttab"); final Map secondTab = - (Map) report.getMetaData().get("secondtab"); - assertEquals("[FILTERED]", firstTab.get("testfilter1")); - assertEquals("[FILTERED]", firstTab.get("testfilter2")); - assertEquals("secretpassword", firstTab.get("testfilter3")); - assertEquals("[FILTERED]", secondTab.get("testfilter1")); + (Map) report.getMetadata().get("secondtab"); + assertEquals("[REDACTED]", firstTab.get("testredact1")); + assertEquals("[REDACTED]", firstTab.get("testredact2")); + assertEquals("secretpassword", firstTab.get("testredact3")); + assertEquals("[REDACTED]", secondTab.get("testredact1")); } @Override @@ -188,30 +189,30 @@ public void close() { assertTrue(bugsnag.notify(new Throwable(), new Callback() { @Override public void beforeNotify(Report report) { - report.addToTab("firsttab", "testfilter1", "secretpassword"); - report.addToTab("firsttab", "testfilter2", "secretpassword"); - report.addToTab("firsttab", "testfilter3", "secretpassword"); - report.addToTab("secondtab", "testfilter1", "secretpassword"); + report.addToTab("firsttab", "testredact1", "secretpassword"); + report.addToTab("firsttab", "testredact2", "secretpassword"); + report.addToTab("firsttab", "testredact3", "secretpassword"); + report.addToTab("secondtab", "testredact1", "secretpassword"); } })); } @Test - public void testFilterHeaders() { + public void testRedactHeaders() { bugsnag.setDelivery(new Delivery() { @SuppressWarnings("unchecked") @Override public void deliver(Serializer serializer, Object object, Map headers) { Report report = ((Notification) object).getEvents().get(0); Map requestTab = - (Map) report.getMetaData().get("request"); + (Map) report.getMetadata().get("request"); Map headersMap = (Map) requestTab.get("headers"); - assertEquals("[FILTERED]", headersMap.get("Authorization")); + assertEquals("[REDACTED]", headersMap.get("Authorization")); assertEquals("User:Password", headersMap.get("authorization")); - assertEquals("[FILTERED]", headersMap.get("Cookie")); + assertEquals("[REDACTED]", headersMap.get("Cookie")); assertEquals("123456ABCDEF", headersMap.get("cookie")); } diff --git a/bugsnag/src/test/java/com/bugsnag/JakartaServletCallbackTest.java b/bugsnag/src/test/java/com/bugsnag/JakartaServletCallbackTest.java index 5bd78ec4..00ad7997 100644 --- a/bugsnag/src/test/java/com/bugsnag/JakartaServletCallbackTest.java +++ b/bugsnag/src/test/java/com/bugsnag/JakartaServletCallbackTest.java @@ -85,7 +85,7 @@ public void testRequestMetadataAdded() { JakartaServletCallback callback = new JakartaServletCallback(); callback.beforeNotify(report); - Map metadata = report.getMetaData(); + Map metadata = report.getMetadata(); assertTrue(metadata.containsKey("request")); Map request = (Map) metadata.get("request"); @@ -100,10 +100,10 @@ public void testRequestMetadataAdded() { assertEquals("some-data-1,some-data-2", headers.get("X-Custom-Header")); // Make sure that actual Authorization header value is not in the report - assertEquals("[FILTERED]", headers.get("Authorization")); + assertEquals("[REDACTED]", headers.get("Authorization")); // Make sure that actual cookies are not in the report - assertEquals("[FILTERED]", headers.get("Cookie")); + assertEquals("[REDACTED]", headers.get("Cookie")); assertTrue(request.containsKey("params")); Map params = (Map) request.get("params"); diff --git a/bugsnag/src/test/java/com/bugsnag/JavaxServletCallbackTest.java b/bugsnag/src/test/java/com/bugsnag/JavaxServletCallbackTest.java deleted file mode 100644 index bd51a02b..00000000 --- a/bugsnag/src/test/java/com/bugsnag/JavaxServletCallbackTest.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.bugsnag; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.bugsnag.callbacks.JavaxServletCallback; - -import com.bugsnag.servlet.BugsnagServletRequestListener; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import javax.servlet.ServletContext; -import javax.servlet.ServletRequestEvent; -import javax.servlet.http.HttpServletRequest; - -public class JavaxServletCallbackTest { - - private Bugsnag bugsnag; - - /** - * Generate a new request instance which will be read by the servlet - * context and callback - */ - @Before - public void setUp() { - bugsnag = new Bugsnag("apikey", false); - bugsnag.setDelivery(null); - - HttpServletRequest request = mock(HttpServletRequest.class); - - Map params = new HashMap(); - params.put("account", new String[]{"Acme Co"}); - params.put("name", new String[]{"Bill"}); - when(request.getParameterMap()).thenReturn(params); - - when(request.getMethod()).thenReturn("PATCH"); - when(request.getRequestURL()).thenReturn(new StringBuffer("/foo/bar")); - when(request.getRequestURI()).thenReturn("/foo/bar"); - when(request.getRemoteAddr()).thenReturn("12.0.4.57"); - - when(request.getHeaderNames()).thenReturn( - stringsToEnumeration( - "Content-Type", - "Content-Length", - "X-Custom-Header", - "Authorization", - "Cookie")); - when(request.getHeaders("Content-Type")).thenReturn( - stringsToEnumeration("application/json")); - when(request.getHeaders("Content-Length")).thenReturn( - stringsToEnumeration("54")); - when(request.getHeaders("X-Custom-Header")).thenReturn( - stringsToEnumeration("some-data-1", "some-data-2")); - when(request.getHeaders("Authorization")).thenReturn( - stringsToEnumeration("Basic ABC123")); - when(request.getHeaders("Cookie")).thenReturn( - stringsToEnumeration("name1=val1; name2=val2")); - - ServletContext context = mock(ServletContext.class); - BugsnagServletRequestListener listener = new BugsnagServletRequestListener(); - listener.requestInitialized(new ServletRequestEvent(context, request)); - } - - /** - * Close test Bugsnag - */ - @After - public void closeBugsnag() { - bugsnag.close(); - } - - @SuppressWarnings("unchecked") - @Test - public void testRequestMetadataAdded() { - Report report = generateReport(new java.lang.Exception("Spline reticulation failed")); - JavaxServletCallback callback = new JavaxServletCallback(); - callback.beforeNotify(report); - - Map metadata = report.getMetaData(); - assertTrue(metadata.containsKey("request")); - - Map request = (Map) metadata.get("request"); - assertEquals("/foo/bar", request.get("url")); - assertEquals("PATCH", request.get("method")); - assertEquals("12.0.4.57", request.get("clientIp")); - - assertTrue(request.containsKey("headers")); - Map headers = (Map) request.get("headers"); - assertEquals("application/json", headers.get("Content-Type")); - assertEquals("54", headers.get("Content-Length")); - assertEquals("some-data-1,some-data-2", headers.get("X-Custom-Header")); - - // Make sure that actual Authorization header value is not in the report - assertEquals("[FILTERED]", headers.get("Authorization")); - - // Make sure that actual cookies are not in the report - assertEquals("[FILTERED]", headers.get("Cookie")); - - assertTrue(request.containsKey("params")); - Map params = (Map) request.get("params"); - assertTrue(params.containsKey("account")); - String[] account = params.get("account"); - assertEquals("Acme Co", account[0]); - - assertTrue(params.containsKey("name")); - String[] name = params.get("name"); - assertEquals("Bill", name[0]); - } - - @Test - public void testRequestContextSet() { - Report report = generateReport(new java.lang.Exception("Spline reticulation failed")); - JavaxServletCallback callback = new JavaxServletCallback(); - callback.beforeNotify(report); - - assertEquals("PATCH /foo/bar", report.getContext()); - } - - @Test - public void testExistingContextNotOverridden() { - Report report = generateReport(new java.lang.Exception("Spline reticulation failed")); - report.setContext("Honey nut corn flakes"); - JavaxServletCallback callback = new JavaxServletCallback(); - callback.beforeNotify(report); - - assertEquals("Honey nut corn flakes", report.getContext()); - } - - private Report generateReport(java.lang.Exception exception) { - return bugsnag.buildReport(exception); - } - - private Enumeration stringsToEnumeration(String... strings) { - return Collections.enumeration(Arrays.asList(strings)); - } -} diff --git a/bugsnag/src/test/java/com/bugsnag/MetaDataTest.java b/bugsnag/src/test/java/com/bugsnag/MetaDataTest.java deleted file mode 100644 index d2f4b580..00000000 --- a/bugsnag/src/test/java/com/bugsnag/MetaDataTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.bugsnag; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import org.junit.Test; - -import java.util.Map; - -public class MetaDataTest { - - @Test - public void testEmptyMetaData() { - MetaData metaData = new MetaData(); - assertEquals(0, metaData.size()); - } - - @Test - @SuppressWarnings("unchecked") - public void testSingleTabSingleValue() { - MetaData metaData = new MetaData(); - metaData.addToTab("tab-name", "key-1", "value-1"); - - assertEquals(1, metaData.size()); - assertEquals(1, ((Map) metaData.get("tab-name")).size()); - assertEquals("value-1", ((Map) metaData.get("tab-name")).get("key-1")); - } - - @Test - @SuppressWarnings("unchecked") - public void testSingleTabMultipleValues() { - MetaData metaData = new MetaData(); - metaData.addToTab("tab-name", "key-1", "value-1"); - metaData.addToTab("tab-name", "key-2", "value-2"); - - assertEquals(1, metaData.size()); - assertEquals(2, ((Map) metaData.get("tab-name")).size()); - assertEquals("value-1", ((Map) metaData.get("tab-name")).get("key-1")); - assertEquals("value-2", ((Map) metaData.get("tab-name")).get("key-2")); - } - - @Test - @SuppressWarnings("unchecked") - public void testMultipleTabs() { - MetaData metaData = new MetaData(); - metaData.addToTab("tab-name-1", "key-1", "value-1"); - metaData.addToTab("tab-name-2", "key-1", "value-1"); - - assertEquals(2, metaData.size()); - assertEquals(1, ((Map) metaData.get("tab-name-1")).size()); - assertEquals(1, ((Map) metaData.get("tab-name-2")).size()); - assertEquals("value-1", ((Map) metaData.get("tab-name-1")).get("key-1")); - assertEquals("value-1", ((Map) metaData.get("tab-name-1")).get("key-1")); - } - - @Test - @SuppressWarnings("unchecked") - public void testClearTab() { - MetaData metaData = new MetaData(); - metaData.addToTab("tab-name-1", "key-1", "value-1"); - metaData.addToTab("tab-name-2", "key-1", "value-1"); - - assertEquals(2, metaData.size()); - - metaData.clearTab("tab-name-1"); - - assertEquals(1, metaData.size()); - - assertNull(metaData.get("tab-name-1")); - assertEquals(1, ((Map) metaData.get("tab-name-2")).size()); - } -} diff --git a/bugsnag/src/test/java/com/bugsnag/MetadataTest.java b/bugsnag/src/test/java/com/bugsnag/MetadataTest.java new file mode 100644 index 00000000..a28c4975 --- /dev/null +++ b/bugsnag/src/test/java/com/bugsnag/MetadataTest.java @@ -0,0 +1,72 @@ +package com.bugsnag; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Test; + +import java.util.Map; + +public class MetadataTest { + + @Test + public void testEmptyMetadata() { + Metadata metadata = new Metadata(); + assertEquals(0, metadata.size()); + } + + @Test + @SuppressWarnings("unchecked") + public void testSingleTabSingleValue() { + Metadata metadata = new Metadata(); + metadata.addToTab("tab-name", "key-1", "value-1"); + + assertEquals(1, metadata.size()); + assertEquals(1, ((Map) metadata.get("tab-name")).size()); + assertEquals("value-1", ((Map) metadata.get("tab-name")).get("key-1")); + } + + @Test + @SuppressWarnings("unchecked") + public void testSingleTabMultipleValues() { + Metadata metadata = new Metadata(); + metadata.addToTab("tab-name", "key-1", "value-1"); + metadata.addToTab("tab-name", "key-2", "value-2"); + + assertEquals(1, metadata.size()); + assertEquals(2, ((Map) metadata.get("tab-name")).size()); + assertEquals("value-1", ((Map) metadata.get("tab-name")).get("key-1")); + assertEquals("value-2", ((Map) metadata.get("tab-name")).get("key-2")); + } + + @Test + @SuppressWarnings("unchecked") + public void testMultipleTabs() { + Metadata metadata = new Metadata(); + metadata.addToTab("tab-name-1", "key-1", "value-1"); + metadata.addToTab("tab-name-2", "key-1", "value-1"); + + assertEquals(2, metadata.size()); + assertEquals(1, ((Map) metadata.get("tab-name-1")).size()); + assertEquals(1, ((Map) metadata.get("tab-name-2")).size()); + assertEquals("value-1", ((Map) metadata.get("tab-name-1")).get("key-1")); + assertEquals("value-1", ((Map) metadata.get("tab-name-1")).get("key-1")); + } + + @Test + @SuppressWarnings("unchecked") + public void testClearTab() { + Metadata metadata = new Metadata(); + metadata.addToTab("tab-name-1", "key-1", "value-1"); + metadata.addToTab("tab-name-2", "key-1", "value-1"); + + assertEquals(2, metadata.size()); + + metadata.clearTab("tab-name-1"); + + assertEquals(1, metadata.size()); + + assertNull(metadata.get("tab-name-1")); + assertEquals(1, ((Map) metadata.get("tab-name-2")).size()); + } +} diff --git a/bugsnag/src/test/java/com/bugsnag/util/FilteredMapTest.java b/bugsnag/src/test/java/com/bugsnag/RedactedMapTest.java similarity index 50% rename from bugsnag/src/test/java/com/bugsnag/util/FilteredMapTest.java rename to bugsnag/src/test/java/com/bugsnag/RedactedMapTest.java index 32bf424c..46cfb5b4 100644 --- a/bugsnag/src/test/java/com/bugsnag/util/FilteredMapTest.java +++ b/bugsnag/src/test/java/com/bugsnag/RedactedMapTest.java @@ -1,4 +1,4 @@ -package com.bugsnag.util; +package com.bugsnag; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -13,132 +13,132 @@ import java.util.Map; import java.util.Set; -public class FilteredMapTest { +public class RedactedMapTest { - private static final String KEY_UNFILTERED = "unfiltered"; - private static final String KEY_FILTERED = "auth"; + private static final String KEY_UNREDACTED = "unredacted"; + private static final String KEY_REDACTED = "auth"; private static final String KEY_NESTED = "nested"; private static final String KEY_UNMODIFIABLE = "unmodifiable"; - private static final String VAL_UNFILTERED = "Foo"; - private static final String VAL_FILTERED = "Bar"; - private static final String PLACEHOLDER_FILTERED = "[FILTERED]"; + private static final String VAL_UNREDACTED = "Foo"; + private static final String VAL_REDACTED = "Bar"; + private static final String PLACEHOLDER_REDACTED = "[REDACTED]"; - private Map filteredMap; + private Map redactedMap; /** - * Creates a map with filtered, unfiltered, and nested values + * Creates a map with redacted, unredacted, and nested values * @throws Exception an exception */ @Before public void setUp() { HashMap map = new HashMap(); - map.put(KEY_UNFILTERED, VAL_UNFILTERED); - map.put(KEY_FILTERED, VAL_FILTERED); + map.put(KEY_UNREDACTED, VAL_UNREDACTED); + map.put(KEY_REDACTED, VAL_REDACTED); HashMap nestedMap = new HashMap(); - nestedMap.put(KEY_UNFILTERED, VAL_UNFILTERED); - nestedMap.put(KEY_FILTERED, VAL_FILTERED); + nestedMap.put(KEY_UNREDACTED, VAL_UNREDACTED); + nestedMap.put(KEY_REDACTED, VAL_REDACTED); map.put(KEY_NESTED, nestedMap); map.put(KEY_UNMODIFIABLE, Collections.unmodifiableMap(nestedMap)); - this.filteredMap = new FilteredMap(map, Collections.singleton(KEY_FILTERED)); + this.redactedMap = new RedactedMap(map, Collections.singleton(KEY_REDACTED)); } @Test public void testSize() { - assertEquals(4, filteredMap.size()); + assertEquals(4, redactedMap.size()); } @Test public void testIsEmpty() { - assertFalse(filteredMap.isEmpty()); + assertFalse(redactedMap.isEmpty()); Map map = Collections.emptyMap(); - FilteredMap emptyMap = new FilteredMap(map, Collections.emptyList()); + RedactedMap emptyMap = new RedactedMap(map, Collections.emptyList()); assertTrue(emptyMap.isEmpty()); } @Test public void testClear() { - assertEquals(4, filteredMap.size()); - filteredMap.clear(); - assertTrue(filteredMap.isEmpty()); + assertEquals(4, redactedMap.size()); + redactedMap.clear(); + assertTrue(redactedMap.isEmpty()); } @Test public void testContainsKey() { - assertTrue(filteredMap.containsKey(KEY_FILTERED)); - assertTrue(filteredMap.containsKey(KEY_UNFILTERED)); - assertTrue(filteredMap.containsKey(KEY_NESTED)); - assertFalse(filteredMap.containsKey("fake")); + assertTrue(redactedMap.containsKey(KEY_REDACTED)); + assertTrue(redactedMap.containsKey(KEY_UNREDACTED)); + assertTrue(redactedMap.containsKey(KEY_NESTED)); + assertFalse(redactedMap.containsKey("fake")); } @Test public void testRemove() { HashMap map = new HashMap(); - map.put(KEY_UNFILTERED, VAL_UNFILTERED); - map.put(KEY_FILTERED, VAL_FILTERED); + map.put(KEY_UNREDACTED, VAL_UNREDACTED); + map.put(KEY_REDACTED, VAL_REDACTED); HashMap emptyMap = new HashMap(); - Set filters = Collections.singleton(KEY_FILTERED); - Map removeMap = new FilteredMap(emptyMap, filters); + Set keys = Collections.singleton(KEY_REDACTED); + Map removeMap = new RedactedMap(emptyMap, keys); removeMap.putAll(map); assertEquals(2, removeMap.size()); - removeMap.remove(KEY_FILTERED); + removeMap.remove(KEY_REDACTED); assertEquals(1, removeMap.size()); - removeMap.remove(KEY_UNFILTERED); + removeMap.remove(KEY_UNREDACTED); assertEquals(0, removeMap.size()); } @Test public void testGet() { - assertEquals(PLACEHOLDER_FILTERED, filteredMap.get(KEY_FILTERED)); - assertEquals(VAL_UNFILTERED, filteredMap.get(KEY_UNFILTERED)); + assertEquals(PLACEHOLDER_REDACTED, redactedMap.get(KEY_REDACTED)); + assertEquals(VAL_UNREDACTED, redactedMap.get(KEY_UNREDACTED)); - Object actual = filteredMap.get(KEY_NESTED); - assertTrue(actual instanceof FilteredMap); + Object actual = redactedMap.get(KEY_NESTED); + assertTrue(actual instanceof RedactedMap); @SuppressWarnings("unchecked") Map nestedMap = (Map) actual; - assertEquals(VAL_UNFILTERED, nestedMap.get(KEY_UNFILTERED)); - assertEquals(PLACEHOLDER_FILTERED, nestedMap.get(KEY_FILTERED)); + assertEquals(VAL_UNREDACTED, nestedMap.get(KEY_UNREDACTED)); + assertEquals(PLACEHOLDER_REDACTED, nestedMap.get(KEY_REDACTED)); } @Test public void testKeySet() { - Set keySet = filteredMap.keySet(); + Set keySet = redactedMap.keySet(); assertEquals(4, keySet.size()); - assertTrue(keySet.contains(KEY_FILTERED)); - assertTrue(keySet.contains(KEY_UNFILTERED)); + assertTrue(keySet.contains(KEY_REDACTED)); + assertTrue(keySet.contains(KEY_UNREDACTED)); assertTrue(keySet.contains(KEY_NESTED)); } @Test public void testValues() { - Collection values = filteredMap.values(); + Collection values = redactedMap.values(); assertEquals(4, values.size()); - assertTrue(values.contains(VAL_UNFILTERED)); - assertTrue(values.contains(PLACEHOLDER_FILTERED)); + assertTrue(values.contains(VAL_UNREDACTED)); + assertTrue(values.contains(PLACEHOLDER_REDACTED)); - values.remove(PLACEHOLDER_FILTERED); - values.remove(VAL_UNFILTERED); + values.remove(PLACEHOLDER_REDACTED); + values.remove(VAL_UNREDACTED); Object nestedObj = values.toArray(new Object[1])[0]; - assertTrue(nestedObj instanceof FilteredMap); + assertTrue(nestedObj instanceof RedactedMap); @SuppressWarnings("unchecked") Map nestedMap = (Map) nestedObj; values = nestedMap.values(); assertEquals(2, values.size()); - assertTrue(values.contains(VAL_UNFILTERED)); - assertTrue(values.contains(PLACEHOLDER_FILTERED)); + assertTrue(values.contains(VAL_UNREDACTED)); + assertTrue(values.contains(PLACEHOLDER_REDACTED)); } @Test public void testEntrySet() { - Set> entries = filteredMap.entrySet(); + Set> entries = redactedMap.entrySet(); assertEquals(4, entries.size()); int expectedCount = 0; @@ -146,18 +146,18 @@ public void testEntrySet() { for (Map.Entry entry : entries) { String key = entry.getKey(); - if (key.equals(KEY_FILTERED)) { + if (key.equals(KEY_REDACTED)) { expectedCount++; - assertEquals(PLACEHOLDER_FILTERED, entry.getValue()); + assertEquals(PLACEHOLDER_REDACTED, entry.getValue()); - } else if (key.equals(KEY_UNFILTERED)) { + } else if (key.equals(KEY_UNREDACTED)) { expectedCount++; - assertEquals(VAL_UNFILTERED, entry.getValue()); + assertEquals(VAL_UNREDACTED, entry.getValue()); } else if (key.equals(KEY_NESTED)) { expectedCount++; Object value = entry.getValue(); - assertTrue(value instanceof FilteredMap); + assertTrue(value instanceof RedactedMap); } else if (key.equals(KEY_UNMODIFIABLE)) { expectedCount++; diff --git a/bugsnag/src/test/java/com/bugsnag/SessionTrackerTest.java b/bugsnag/src/test/java/com/bugsnag/SessionTrackerTest.java index 65d71ba3..d1dcf9ec 100644 --- a/bugsnag/src/test/java/com/bugsnag/SessionTrackerTest.java +++ b/bugsnag/src/test/java/com/bugsnag/SessionTrackerTest.java @@ -14,6 +14,7 @@ import org.junit.Before; import org.junit.Test; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; @@ -133,7 +134,7 @@ public void run() { @Test public void disabledReleaseStage() { - configuration.notifyReleaseStages = new String[]{"prod"}; + configuration.enabledReleaseStages = Collections.singleton("prod"); configuration.releaseStage = "dev"; sessionTracker.startSession(new Date(), false); assertNull(sessionTracker.getSession()); @@ -141,7 +142,7 @@ public void disabledReleaseStage() { @Test public void enabledReleaseStage() { - configuration.notifyReleaseStages = new String[]{"prod"}; + configuration.enabledReleaseStages = Collections.singleton("prod"); configuration.releaseStage = "prod"; sessionTracker.startSession(new Date(), false); assertNotNull(sessionTracker.getSession()); diff --git a/bugsnag/src/test/java/com/bugsnag/ThreadMetaDataTest.java b/bugsnag/src/test/java/com/bugsnag/ThreadMetadataTest.java similarity index 59% rename from bugsnag/src/test/java/com/bugsnag/ThreadMetaDataTest.java rename to bugsnag/src/test/java/com/bugsnag/ThreadMetadataTest.java index 26589564..2aa1fe07 100644 --- a/bugsnag/src/test/java/com/bugsnag/ThreadMetaDataTest.java +++ b/bugsnag/src/test/java/com/bugsnag/ThreadMetadataTest.java @@ -12,7 +12,7 @@ import java.util.Map; -public class ThreadMetaDataTest { +public class ThreadMetadataTest { private StubNotificationDelivery delivery; private Delivery originalDelivery; @@ -39,39 +39,39 @@ public void revertDelivery() { } @Test - public void testMetaDataClearAll() { + public void testMetadataClearAll() { - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "some key", "some thread value"); + // Add some thread metadata + Bugsnag.addThreadMetadata("thread", "some key", "some thread value"); bugsnag.notify(new RuntimeException("test")); - Bugsnag.clearThreadMetaData(); + Bugsnag.clearThreadMetadata(); bugsnag.notify(new RuntimeException("test")); // Check that two reports were sent to Bugsnag assertEquals(2, delivery.getNotifications().size()); - // Check the meta data is added to the first report + // Check the metadata is added to the first report Notification notification = delivery.getNotifications().get(0); Report report = notification.getEvents().get(0); - assertTrue(report.getMetaData().containsKey("thread")); - assertEquals("some thread value", getMetaDataMap(notification, "thread").get("some key")); + assertTrue(report.getMetadata().containsKey("thread")); + assertEquals("some thread value", getMetadataMap(notification, "thread").get("some key")); - // Check the meta data is not added to the second report + // Check the metadata is not added to the second report notification = delivery.getNotifications().get(1); report = notification.getEvents().get(0); - assertFalse(report.getMetaData().containsKey("thread")); + assertFalse(report.getMetadata().containsKey("thread")); } @Test - public void testMetaDataClearTab() { + public void testMetadataClearTab() { - // Add some thread meta data - Bugsnag.addThreadMetaData("tab1", "some key", "some value"); - Bugsnag.addThreadMetaData("tab2", "some key", "some value"); + // Add some thread metadata + Bugsnag.addThreadMetadata("tab1", "some key", "some value"); + Bugsnag.addThreadMetadata("tab2", "some key", "some value"); bugsnag.notify(new RuntimeException("test")); - Bugsnag.clearThreadMetaData("tab2"); + Bugsnag.clearThreadMetadata("tab2"); bugsnag.notify(new RuntimeException("test")); // Check that two reports were sent to Bugsnag @@ -80,28 +80,28 @@ public void testMetaDataClearTab() { // Check that both tabs are populated in the first report Notification notification = delivery.getNotifications().get(0); Report report = notification.getEvents().get(0); - assertTrue(report.getMetaData().containsKey("tab1")); - assertEquals("some value", getMetaDataMap(notification, "tab1").get("some key")); - assertTrue(report.getMetaData().containsKey("tab2")); - assertEquals("some value", getMetaDataMap(notification, "tab2").get("some key")); + assertTrue(report.getMetadata().containsKey("tab1")); + assertEquals("some value", getMetadataMap(notification, "tab1").get("some key")); + assertTrue(report.getMetadata().containsKey("tab2")); + assertEquals("some value", getMetadataMap(notification, "tab2").get("some key")); // Check that only the first tab is in the second tab notification = delivery.getNotifications().get(1); report = notification.getEvents().get(0); - assertTrue(report.getMetaData().containsKey("tab1")); - assertEquals("some value", getMetaDataMap(notification, "tab1").get("some key")); - assertFalse(report.getMetaData().containsKey("tab2")); + assertTrue(report.getMetadata().containsKey("tab1")); + assertEquals("some value", getMetadataMap(notification, "tab1").get("some key")); + assertFalse(report.getMetadata().containsKey("tab2")); } @Test - public void testMetaDataClearKey() { + public void testMetadataClearKey() { - // Add some thread meta data - Bugsnag.addThreadMetaData("tab1", "key1", "some value"); - Bugsnag.addThreadMetaData("tab1", "key2", "some value"); + // Add some thread metadata + Bugsnag.addThreadMetadata("tab1", "key1", "some value"); + Bugsnag.addThreadMetadata("tab1", "key2", "some value"); bugsnag.notify(new RuntimeException("test")); - Bugsnag.clearThreadMetaData("tab1", "key2"); + Bugsnag.clearThreadMetadata("tab1", "key2"); bugsnag.notify(new RuntimeException("test")); // Check that two reports were sent to Bugsnag @@ -110,29 +110,29 @@ public void testMetaDataClearKey() { // Check that both keys are populated in the first report Notification notification = delivery.getNotifications().get(0); Report report = notification.getEvents().get(0); - assertTrue(report.getMetaData().containsKey("tab1")); - assertEquals("some value", getMetaDataMap(notification, "tab1").get("key1")); - assertEquals("some value", getMetaDataMap(notification, "tab1").get("key2")); + assertTrue(report.getMetadata().containsKey("tab1")); + assertEquals("some value", getMetadataMap(notification, "tab1").get("key1")); + assertEquals("some value", getMetadataMap(notification, "tab1").get("key2")); // Check that only the first tab is in the second tab notification = delivery.getNotifications().get(1); report = notification.getEvents().get(0); - assertTrue(report.getMetaData().containsKey("tab1")); - assertEquals("some value", getMetaDataMap(notification, "tab1").get("key1")); - assertFalse(getMetaDataMap(notification, "tab1").containsKey("key2")); + assertTrue(report.getMetadata().containsKey("tab1")); + assertEquals("some value", getMetadataMap(notification, "tab1").get("key1")); + assertFalse(getMetadataMap(notification, "tab1").containsKey("key2")); } @Test - public void testInnerThreadMetaData() { + public void testInnerThreadMetadata() { - // Add some thread meta data in the outer thread - Bugsnag.addThreadMetaData("outerthread", "some key", "value should not be in report"); + // Add some thread metadata in the outer thread + Bugsnag.addThreadMetadata("outerthread", "some key", "value should not be in report"); Thread thread = new Thread(new Runnable() { @Override public void run() { - // Add thread meta data which should get associated with the exception - Bugsnag.addThreadMetaData("innerthread", "some key", "value should be in report"); + // Add thread metadata which should get associated with the exception + Bugsnag.addThreadMetadata("innerthread", "some key", "value should be in report"); // Notify to Bugsnag bugsnag.notify(new RuntimeException("test")); @@ -151,26 +151,26 @@ public void run() { Notification notification = delivery.getNotifications().get(0); Report report = notification.getEvents().get(0); - assertTrue(report.getMetaData().containsKey("innerthread")); + assertTrue(report.getMetadata().containsKey("innerthread")); assertEquals("value should be in report", - getMetaDataMap(notification, "innerthread").get("some key")); + getMetadataMap(notification, "innerthread").get("some key")); - assertFalse(report.getMetaData().containsKey("outerthread")); + assertFalse(report.getMetadata().containsKey("outerthread")); } @Test - public void testUnhandledThreadMetaDataRemoval() { + public void testUnhandledThreadMetadataRemoval() { Thread thread = new Thread(new Runnable() { @Override public void run() { - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "key1", "should be cleared from meta data"); + // Add some thread metadata + Bugsnag.addThreadMetadata("thread", "key1", "should be cleared from metadata"); - Bugsnag.clearThreadMetaData(); + Bugsnag.clearThreadMetadata(); - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "key2", "should be included in meta data"); + // Add some thread metadata + Bugsnag.addThreadMetadata("thread", "key2", "should be included in metadata"); // Thrown unhandled exception throw new RuntimeException("test"); @@ -189,23 +189,23 @@ public void run() { Notification notification = delivery.getNotifications().get(0); Report report = notification.getEvents().get(0); - assertTrue(report.getMetaData().containsKey("thread")); - assertFalse(getMetaDataMap(notification, "thread").containsKey("key1")); - assertEquals("should be included in meta data", - getMetaDataMap(notification, "thread").get("key2")); + assertTrue(report.getMetadata().containsKey("thread")); + assertFalse(getMetadataMap(notification, "thread").containsKey("key1")); + assertEquals("should be included in metadata", + getMetadataMap(notification, "thread").get("key2")); } @Test - public void testUnhandledThreadMetaData() { + public void testUnhandledThreadMetadata() { - // Add some thread meta data in the outer thread - Bugsnag.addThreadMetaData("outerthread", "some key", "value should not be in report"); + // Add some thread metadata in the outer thread + Bugsnag.addThreadMetadata("outerthread", "some key", "value should not be in report"); Thread thread = new Thread(new Runnable() { @Override public void run() { - // Add thread meta data which should get associated with the exception - Bugsnag.addThreadMetaData("innerthread", "some key", "value should be in report"); + // Add thread metadata which should get associated with the exception + Bugsnag.addThreadMetadata("innerthread", "some key", "value should be in report"); // Thrown unhandled exception throw new RuntimeException("test"); @@ -224,22 +224,22 @@ public void run() { Notification notification = delivery.getNotifications().get(0); Report report = notification.getEvents().get(0); - assertTrue(report.getMetaData().containsKey("innerthread")); + assertTrue(report.getMetadata().containsKey("innerthread")); assertEquals("value should be in report", - getMetaDataMap(notification, "innerthread").get("some key")); + getMetadataMap(notification, "innerthread").get("some key")); - assertFalse(report.getMetaData().containsKey("outerthread")); + assertFalse(report.getMetadata().containsKey("outerthread")); } /** - * Gets a hashmap key from the meta data in a notification + * Gets a hashmap key from the metadata in a notification * * @param notification The notification * @param key The key to get * @return The hash map */ @SuppressWarnings (value = "unchecked") - private Map getMetaDataMap(Notification notification, String key) { - return ((Map) notification.getEvents().get(0).getMetaData().get(key)); + private Map getMetadataMap(Notification notification, String key) { + return ((Map) notification.getEvents().get(0).getMetadata().get(key)); } } diff --git a/bugsnag/src/test/resources/logback.xml b/bugsnag/src/test/resources/logback.xml index 4450bab2..109091af 100644 --- a/bugsnag/src/test/resources/logback.xml +++ b/bugsnag/src/test/resources/logback.xml @@ -7,19 +7,19 @@ gradleTask - password - credit_card_number + password + credit_card_number - java.io.IOException - com.example.Custom + java.io.IOException + com.example.Custom - test - development + test + development com.company.package1 com.company.package2 - + logbackTab @@ -31,7 +31,7 @@ logbackValue2 - + true diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 37e5c3ff..00000000 --- a/build.gradle +++ /dev/null @@ -1,15 +0,0 @@ -buildscript { - repositories { - mavenCentral() - maven { - url = uri("https://plugins.gradle.org/m2/") - } - } -} - -gradle.projectsEvaluated { - tasks.withType(JavaCompile) { - // fail build on warnings, disable options complaining about Java 6 compatibility when building with JDK 7+ - options.compilerArgs << "-Xlint:all" << "-Werror" << "-Xlint:-options" - } -} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..67a917c9 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,22 @@ +buildscript { + repositories { + mavenCentral() + maven { + url = uri("https://plugins.gradle.org/m2/") + } + } +} + +gradle.projectsEvaluated { + tasks.withType().configureEach { + // fail build on warnings, disable options complaining about Java 6 compatibility when building with JDK 7+ + options.compilerArgs.addAll(listOf("-Xlint:all", "-Werror", "-Xlint:-options")) + } +} + +tasks.register("publishToTestRepoAll") { + dependsOn(subprojects.mapNotNull { + tasks.findByPath("${it.path}:publishAllPublicationsToTestRepository") + }) +} + diff --git a/common.gradle b/common.gradle deleted file mode 100644 index d69f4398..00000000 --- a/common.gradle +++ /dev/null @@ -1,29 +0,0 @@ -ext { - javaxServletApiVersion = "3.1.0" - jakartaServletApiVersion = "5.0.0" - logbackVersion = "1.2.3" - slf4jApiVersion = "1.7.25" - junitVersion = "4.13.2" - mockitoVersion = "5.0.0" -} - -if (JavaVersion.current().isJava8Compatible()) { - apply plugin: 'checkstyle' -} - -if (project.hasProperty('releasing') && project.depth <= 1) { - apply from: "../release.gradle" -} - -test { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - } -} - -if (JavaVersion.current().isJava8Compatible()) { - checkstyle { - toolVersion = "8.18" - configFile = new File(rootDir, "config/checkstyle/checkstyle.xml") - } -} \ No newline at end of file diff --git a/common.gradle.kts b/common.gradle.kts new file mode 100644 index 00000000..d02d54dc --- /dev/null +++ b/common.gradle.kts @@ -0,0 +1,16 @@ +// Version catalog is now used - see gradle/libs.versions.toml +apply(plugin = "checkstyle") + +if (project.hasProperty("releasing") && project.depth <= 1) { + apply(from = "../release.gradle.kts") +} +tasks.named("test") { + testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + } +} + +configure { + toolVersion = "8.18" + configFile = file("${rootDir}/config/checkstyle/checkstyle.xml") +} diff --git a/docker-compose.yml b/docker-compose.yml index 242c3de5..78db1435 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,16 +9,12 @@ services: dockerfile: dockerfiles/Dockerfile.java-common volumes: - .:/app - java8-mazerunner: - build: - context: . - dockerfile: dockerfiles/Dockerfile.java8-mazerunner - volumes: - - .:/app java17-mazerunner: build: context: . dockerfile: dockerfiles/Dockerfile.java17-mazerunner + volumes: + - ./maze_output:/app/maze_output java-publisher: build: context: . diff --git a/dockerfiles/Dockerfile.java-common b/dockerfiles/Dockerfile.java-common index 2d4d1224..e3ce526f 100644 --- a/dockerfiles/Dockerfile.java-common +++ b/dockerfiles/Dockerfile.java-common @@ -1,4 +1,4 @@ -FROM openjdk:17-jdk-slim +FROM eclipse-temurin:17.0.13_11-jdk-jammy WORKDIR /app RUN apt-get update > /dev/null @@ -9,5 +9,5 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get install -y zip COPY gradlew gradle.properties /app/ COPY gradle/ /app/gradle/ ENV GRADLE_OPTS="-Dorg.gradle.daemon=false" -COPY settings.gradle /app/ +COPY settings.gradle.kts /app/ RUN ./gradlew diff --git a/dockerfiles/Dockerfile.java-publisher b/dockerfiles/Dockerfile.java-publisher index c213d08e..904e3b89 100644 --- a/dockerfiles/Dockerfile.java-publisher +++ b/dockerfiles/Dockerfile.java-publisher @@ -5,7 +5,7 @@ WORKDIR /app # Copy gradle files COPY gradlew gradle.properties /app/ COPY gradle/ /app/gradle/ -COPY build.gradle settings.gradle release.gradle common.gradle /app/ +COPY build.gradle.kts settings.gradle.kts release.gradle.kts common.gradle.kts /app/ # Copy sdk source files COPY bugsnag/ bugsnag/ diff --git a/dockerfiles/Dockerfile.java17-mazerunner b/dockerfiles/Dockerfile.java17-mazerunner index f4fef7ff..8ca1b00d 100644 --- a/dockerfiles/Dockerfile.java17-mazerunner +++ b/dockerfiles/Dockerfile.java17-mazerunner @@ -1,4 +1,5 @@ -FROM tomcat:10-jdk17-openjdk-slim +FROM tomcat:10.1-jdk17-temurin-jammy + WORKDIR /app RUN apt-get update && DEBIAN_FRONTEND=noninteractive \ @@ -9,7 +10,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive \ COPY gradlew gradle.properties /app/ COPY gradle/ /app/gradle/ ENV GRADLE_OPTS="-Dorg.gradle.daemon=false" -COPY settings.gradle /app/ +COPY settings.gradle.kts /app/ RUN ./gradlew # Copy repo into docker diff --git a/dockerfiles/Dockerfile.java8-mazerunner b/dockerfiles/Dockerfile.java8-mazerunner deleted file mode 100644 index 123f0e30..00000000 --- a/dockerfiles/Dockerfile.java8-mazerunner +++ /dev/null @@ -1,20 +0,0 @@ -FROM tomcat:9.0.56-jdk8 -WORKDIR /app - -RUN apt-get update && DEBIAN_FRONTEND=noninteractive \ - apt-get install -y -q docker-compose bundler libcurl4-openssl-dev unzip - -# Force download of gradle zip early to avoid repeating -# if Docker cache is invalidated by branch changes. -COPY gradlew gradle.properties /app/ -COPY gradle/ /app/gradle/ -ENV GRADLE_OPTS="-Dorg.gradle.daemon=false" -COPY settings.gradle /app/ -RUN ./gradlew - -# Copy repo into docker -COPY . /app - -# Setup mazerunner -RUN gem install bundler:1.16.5 -RUN bundle install diff --git a/dockerfiles/Dockerfile.license-audit b/dockerfiles/Dockerfile.license-audit index c94c939f..ed96ff1b 100644 --- a/dockerfiles/Dockerfile.license-audit +++ b/dockerfiles/Dockerfile.license-audit @@ -1,4 +1,4 @@ -FROM openjdk:17-jdk-slim +FROM eclipse-temurin:17.0.13_11-jdk-jammy RUN apt-get update RUN apt-get install -y ruby-full curl @@ -9,7 +9,7 @@ WORKDIR /scan COPY gradle gradle COPY bugsnag bugsnag COPY bugsnag-spring bugsnag-spring -COPY build.gradle common.gradle gradle.properties gradlew gradlew.bat LICENSE release.gradle settings.gradle ./ +COPY build.gradle.kts common.gradle.kts gradle.properties gradlew gradlew.bat LICENSE release.gradle.kts settings.gradle.kts ./ RUN ./gradlew diff --git a/examples/logback/src/main/java/com/bugsnag/example/logback/cli/Application.java b/examples/logback/src/main/java/com/bugsnag/example/logback/cli/Application.java index fc38b4bd..08b77577 100644 --- a/examples/logback/src/main/java/com/bugsnag/example/logback/cli/Application.java +++ b/examples/logback/src/main/java/com/bugsnag/example/logback/cli/Application.java @@ -31,8 +31,8 @@ public static void main(String[] args) throws Exception { }); } - // Add meta data that will be added to all reports on the current thread - Bugsnag.addThreadMetaData("thread tab", "thread key 1", "thread value 1"); + // Add metadata that will be added to all reports on the current thread + Bugsnag.addThreadMetadata("thread tab", "thread key 1", "thread value 1"); // Send a handled exception to Bugsnag LOGGER.info("Sending a handled exception to Bugsnag"); @@ -50,8 +50,8 @@ public static void main(String[] args) throws Exception { LOGGER.info(e.getMessage(), e); } - // Send a handled exception with custom MetaData - LOGGER.info("Sending a handled exception to Bugsnag with custom MetaData"); + // Send a handled exception with custom Metadata + LOGGER.info("Sending a handled exception to Bugsnag with custom Metadata"); try { throw new RuntimeException("Handled exception - custom metadata"); } catch (RuntimeException e) { @@ -76,8 +76,8 @@ public void run() { // Wait for unhandled exception thread to finish before exiting thread.join(); - // Remove the thread meta data so it won't be added to future reports on this thread - Bugsnag.clearThreadMetaData(); + // Remove the thread metadata so it won't be added to future reports on this thread + Bugsnag.clearThreadMetadata(); // Exit the application System.exit(0); diff --git a/examples/logback/src/main/resources/logback.xml b/examples/logback/src/main/resources/logback.xml index 45b5ae69..ae127ffb 100644 --- a/examples/logback/src/main/resources/logback.xml +++ b/examples/logback/src/main/resources/logback.xml @@ -17,27 +17,27 @@ - - + + - - + + - - + + - + - + - - + + - + diff --git a/examples/servlet-javax/README.md b/examples/servlet-javax/README.md deleted file mode 100644 index b81c6e81..00000000 --- a/examples/servlet-javax/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Bugsnag Javax Servlet Example - -Demonstrates how to use Bugsnag in a Servlet-based Java application. - -1. Open `ExampleServlet` and alter the value of `bugsnag = new Bugsnag("YOUR-API-KEY");` to match your API key - -2. Build the app - - ```shell - gradle clean assemble - ``` - -3. Start the web server - - ```shell - gradle appRun - ``` - -4. Cause a crash by visiting [http://localhost:8080/servlet](http://localhost:8080/servlet) - -5. View the captured errors in [your dashboard](https://app.bugsnag.com) diff --git a/examples/servlet-javax/build.gradle b/examples/servlet-javax/build.gradle deleted file mode 100644 index 1e4412f3..00000000 --- a/examples/servlet-javax/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -apply plugin: 'java' -apply plugin: 'war' -apply plugin: 'org.gretty' - -buildscript { - repositories { - mavenCentral() - } - - dependencies { - classpath 'org.gretty:gretty:3.1.1' - } -} - -repositories { - mavenCentral() -} - -dependencies { - runtimeOnly 'org.slf4j:slf4j-simple:1.7.25' - implementation "javax.servlet:javax.servlet-api:3.1.0" - implementation project(':bugsnag') -} - -gretty { - contextPath = '/' - jvmArgs = ['-Dorg.slf4j.simpleLogger.defaultLogLevel=DEBUG'] -} - diff --git a/examples/servlet-javax/src/main/java/com/bugsnag/example/servlet/ErrorHandler.java b/examples/servlet-javax/src/main/java/com/bugsnag/example/servlet/ErrorHandler.java deleted file mode 100644 index 317a517f..00000000 --- a/examples/servlet-javax/src/main/java/com/bugsnag/example/servlet/ErrorHandler.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.bugsnag.example.servlet; - -import com.bugsnag.Bugsnag; - -import java.io.IOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -public class ErrorHandler extends HttpServlet { - - private static final long serialVersionUID = 4926619146717832212L; - - private Bugsnag bugsnag; - - /** - * Error handler to report the error to Bugsnag - */ - public ErrorHandler() { - bugsnag = new Bugsnag("YOUR-API-KEY"); - bugsnag.setProjectPackages("com.bugsnag.example"); - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - // Notify Bugsnag of the exception - Throwable throwable = (Throwable) req.getAttribute("javax.servlet.error.exception"); - bugsnag.notify(throwable); - } -} diff --git a/examples/servlet-javax/src/main/java/com/bugsnag/example/servlet/ExampleServlet.java b/examples/servlet-javax/src/main/java/com/bugsnag/example/servlet/ExampleServlet.java deleted file mode 100644 index a33b7fdc..00000000 --- a/examples/servlet-javax/src/main/java/com/bugsnag/example/servlet/ExampleServlet.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.bugsnag.example.servlet; - -import com.bugsnag.Bugsnag; -import com.bugsnag.Severity; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -public class ExampleServlet extends HttpServlet { - - private static final long serialVersionUID = 1432171052111530587L; - - private Bugsnag bugsnag; - - /** - * Simple servlet example - */ - public ExampleServlet() { - bugsnag = new Bugsnag("YOUR-API-KEY"); - bugsnag.setProjectPackages("com.bugsnag.example"); - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException { - // Send a handled exception to Bugsnag - try { - throw new RuntimeException("Handled exception - default severity"); - } catch (RuntimeException e) { - bugsnag.notify(e); - } - - // Send a handled exception to Bugsnag with info severity - try { - throw new RuntimeException("Handled exception - INFO severity"); - } catch (RuntimeException ex) { - bugsnag.notify(ex, Severity.INFO); - } - - // Throw an exception - not automatically reported so must be handled by the error handler - throw new ServletException("Servlet exception"); - } -} diff --git a/examples/servlet-javax/src/main/webapp/WEB-INF/web.xml b/examples/servlet-javax/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index e34c77b7..00000000 --- a/examples/servlet-javax/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - ExampleServlet - ExampleServlet - com.bugsnag.example.servlet.ExampleServlet - - - ErrorHandler - com.bugsnag.example.servlet.ErrorHandler - - - - ExampleServlet - / - - - ErrorHandler - /ErrorHandler - - - - - javax.servlet.ServletException - /ErrorHandler - - diff --git a/examples/simple/src/main/java/com/bugsnag/example/simple/ExampleApp.java b/examples/simple/src/main/java/com/bugsnag/example/simple/ExampleApp.java index ec6ba056..cfb24441 100644 --- a/examples/simple/src/main/java/com/bugsnag/example/simple/ExampleApp.java +++ b/examples/simple/src/main/java/com/bugsnag/example/simple/ExampleApp.java @@ -47,7 +47,7 @@ public void beforeNotify(Report report) { bugsnag.notify(e, Severity.INFO); } - // Send a handled exception with custom MetaData + // Send a handled exception with custom Metadata try { throw new RuntimeException("Handled exception - custom metadata"); } catch (RuntimeException e) { diff --git a/examples/spring-web/src/main/java/com/bugsnag/example/spring/web/ApplicationRestController.java b/examples/spring-web/src/main/java/com/bugsnag/example/spring/web/ApplicationRestController.java index b5d23736..df5a5796 100644 --- a/examples/spring-web/src/main/java/com/bugsnag/example/spring/web/ApplicationRestController.java +++ b/examples/spring-web/src/main/java/com/bugsnag/example/spring/web/ApplicationRestController.java @@ -65,7 +65,7 @@ public String sendHandledExceptionInfo() { @RequestMapping("/send-handled-exception-with-metadata") public String sendHandledExceptionWithMetadata() { - LOGGER.info("Sending a handled exception to Bugsnag with custom MetaData"); + LOGGER.info("Sending a handled exception to Bugsnag with custom Metadata"); try { throw new RuntimeException("Handled exception - custom metadata"); } catch (RuntimeException e) { @@ -79,7 +79,7 @@ public void beforeNotify(Report report) { }); } - return exampleWebsiteLinks + "
Sent a handled exception to Bugsnag with custom MetaData"; + return exampleWebsiteLinks + "
Sent a handled exception to Bugsnag with custom Metadata"; } @RequestMapping("/send-unhandled-exception") diff --git a/examples/spring-web/src/main/java/com/bugsnag/example/spring/web/Config.java b/examples/spring-web/src/main/java/com/bugsnag/example/spring/web/Config.java index e5ba4493..0481f59f 100644 --- a/examples/spring-web/src/main/java/com/bugsnag/example/spring/web/Config.java +++ b/examples/spring-web/src/main/java/com/bugsnag/example/spring/web/Config.java @@ -50,7 +50,7 @@ public void beforeNotify(Report report) { public String exampleWebsiteLinks() { return "Send a handled exception to Bugsnag
" + "Send a handled exception to Bugsnag with INFO severity
" - + "Send a handled exception to Bugsnag with custom MetaData
" + + "Send a handled exception to Bugsnag with custom Metadata
" + "Send an unhandled exception to Bugsnag
" + "Send an unhandled exception to Bugsnag from an async method
" + "Send an unhandled exception to Bugsnag from an async method that returns a Future
" diff --git a/examples/spring/src/main/java/com/bugsnag/example/spring/cli/ApplicationCommandLineRunner.java b/examples/spring/src/main/java/com/bugsnag/example/spring/cli/ApplicationCommandLineRunner.java index 7d6cdd7c..6e201859 100644 --- a/examples/spring/src/main/java/com/bugsnag/example/spring/cli/ApplicationCommandLineRunner.java +++ b/examples/spring/src/main/java/com/bugsnag/example/spring/cli/ApplicationCommandLineRunner.java @@ -43,8 +43,8 @@ public void run(final String... args) throws Exception { bugsnag.notify(e, Severity.INFO); } - // Send a handled exception with custom MetaData - LOGGER.info("Sending a handled exception to Bugsnag with custom MetaData"); + // Send a handled exception with custom Metadata + LOGGER.info("Sending a handled exception to Bugsnag with custom Metadata"); try { throw new RuntimeException("Handled exception - custom metadata"); } catch (RuntimeException e) { diff --git a/features/filtering_metadata.feature b/features/filtering_metadata.feature deleted file mode 100644 index db8aacbf..00000000 --- a/features/filtering_metadata.feature +++ /dev/null @@ -1,54 +0,0 @@ -Feature: Metadata is filtered - -Scenario: Using the default metadata filter - When I run "AutoFilterScenario" with the defaults - And I wait to receive an error - And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier - And the exception "message" equals "AutoFilterScenario" - And the event "metaData.custom.foo" equals "hunter2" - And the event "metaData.custom.password" equals "[FILTERED]" - And the event "metaData.user.password" equals "[FILTERED]" - -Scenario: Adding a custom metadata filter - When I run "ManualFilterScenario" with the defaults - And I wait to receive an error - And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier - And the exception "message" equals "ManualFilterScenario" - And the event "metaData.custom.foo" equals "[FILTERED]" - And the event "metaData.user.foo" equals "[FILTERED]" - And the event "metaData.custom.bar" equals "hunter2" - -Scenario: Adding a thread metadata filter using logback - When I run "LogbackThreadMetaDataScenario" with logback config "meta_data_filter_config.xml" - And I wait to receive an error - And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier - And the exception "message" equals "LogbackThreadMetaDataScenario" - And the event "metaData.thread.foo" equals "[FILTERED]" - And the event "metaData.thread.bar" equals "threadvalue2" - -Scenario: Adding a custom metadata filter using logback - When I run "LogbackMetaDataScenario" with logback config "meta_data_filter_config.xml" - And I wait to receive an error - And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier - And the exception "message" equals "LogbackMetaDataScenario" - And the event "metaData.custom.foo" equals "[FILTERED]" - And the event "metaData.user.foo" equals "[FILTERED]" - And the event "metaData.custom.bar" equals "hunter2" - -Scenario: Using the default metadata filter in Spring Boot app - When I run spring boot "AutoFilterScenario" with the defaults - And I wait to receive an error - And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier - And the exception "message" equals "AutoFilterScenario" - And the event "metaData.custom.foo" equals "hunter2" - And the event "metaData.custom.password" equals "[FILTERED]" - And the event "metaData.user.password" equals "[FILTERED]" - -Scenario: Using the default metadata filter in Spring app - When I run plain Spring "AutoFilterScenario" with the defaults - And I wait to receive an error - And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier - And the exception "message" equals "AutoFilterScenario" - And the event "metaData.custom.foo" equals "hunter2" - And the event "metaData.custom.password" equals "[FILTERED]" - And the event "metaData.user.password" equals "[FILTERED]" diff --git a/features/fixtures/logback/ignore_release_stage_config.xml b/features/fixtures/logback/ignore_release_stage_config.xml index 95b1da88..b8bf5d4c 100644 --- a/features/fixtures/logback/ignore_release_stage_config.xml +++ b/features/fixtures/logback/ignore_release_stage_config.xml @@ -7,8 +7,8 @@ staging 1.0.0 - production - development + production + development http://localhost:9339/notify diff --git a/features/fixtures/logback/ignored_class_config.xml b/features/fixtures/logback/ignored_class_config.xml index 75577a21..fb425538 100644 --- a/features/fixtures/logback/ignored_class_config.xml +++ b/features/fixtures/logback/ignored_class_config.xml @@ -7,7 +7,7 @@ production 1.0.0 - java.lang.RuntimeException + java.lang.RuntimeException http://localhost:9339/notify diff --git a/features/fixtures/logback/meta_data_config.xml b/features/fixtures/logback/meta_data_config.xml index 48704afb..38376a96 100644 --- a/features/fixtures/logback/meta_data_config.xml +++ b/features/fixtures/logback/meta_data_config.xml @@ -7,7 +7,7 @@ production 1.0.0 - + configTab @@ -19,7 +19,7 @@ tabValue2 - + http://localhost:9339/notify diff --git a/features/fixtures/logback/meta_data_filter_config.xml b/features/fixtures/logback/meta_data_filter_config.xml deleted file mode 100644 index e036b689..00000000 --- a/features/fixtures/logback/meta_data_filter_config.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - a35a2a72bd230ac0aa0f52715bbdc6aa - production - 1.0.0 - - foo - - http://localhost:9339/notify - - - - - - diff --git a/features/fixtures/mazerunner/src/main/resources/logback.xml b/features/fixtures/logback/meta_data_redact_config.xml similarity index 93% rename from features/fixtures/mazerunner/src/main/resources/logback.xml rename to features/fixtures/logback/meta_data_redact_config.xml index 60ade3a1..96009aaf 100644 --- a/features/fixtures/mazerunner/src/main/resources/logback.xml +++ b/features/fixtures/logback/meta_data_redact_config.xml @@ -6,9 +6,7 @@ a35a2a72bd230ac0aa0f52715bbdc6aa production 1.0.0 - - testAppType - + foo http://localhost:9339/notify @@ -16,3 +14,4 @@ + diff --git a/features/fixtures/mazerunner/build.gradle b/features/fixtures/mazerunner/build.gradle deleted file mode 100644 index 2425932b..00000000 --- a/features/fixtures/mazerunner/build.gradle +++ /dev/null @@ -1,40 +0,0 @@ -buildscript { - ext { - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -group 'com.bugsnag.mazerunner' -version '1.0-SNAPSHOT' - -sourceCompatibility = '1.8' - -repositories { - mavenCentral() - maven { - url file('../libs').toURI() - } -} - -dependencies { - implementation("org.springframework.boot:spring-boot-starter") - implementation("ch.qos.logback:logback-classic:1.2.3") - - implementation("com.fasterxml.jackson.core:jackson-annotations:2.9.1") - implementation("com.fasterxml.jackson.core:jackson-databind:2.9.1") - implementation("com.bugsnag:bugsnag:9.9.9-test") - implementation project(":scenarios") - - testImplementation group: 'junit', name: 'junit', version: '4.13.2' -} - diff --git a/features/fixtures/mazerunner/build.gradle.kts b/features/fixtures/mazerunner/build.gradle.kts new file mode 100644 index 00000000..bb343ac0 --- /dev/null +++ b/features/fixtures/mazerunner/build.gradle.kts @@ -0,0 +1,36 @@ +plugins { + java + id("org.springframework.boot") version "3.5.6" + id("io.spring.dependency-management") version "1.1.0" +} + +group = "com.bugsnag.mazerunner" +version = "1.0-SNAPSHOT" + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +repositories { + mavenCentral() + maven { + url = file("../libs").toURI() + } +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter") + implementation("ch.qos.logback:logback-classic:1.5.18") + implementation("ch.qos.logback:logback-core:1.5.18") + implementation("org.codehaus.janino:janino:3.1.10") + + implementation("com.fasterxml.jackson.core:jackson-annotations:2.14.1") + implementation("com.fasterxml.jackson.core:jackson-databind:2.14.1") + implementation("com.bugsnag:bugsnag:9.9.9-test") + implementation(project(":scenarios")) + + testImplementation("junit:junit:4.13.2") +} + diff --git a/features/fixtures/mazerunnerplainspring/build.gradle b/features/fixtures/mazerunnerplainspring/build.gradle deleted file mode 100644 index beb828fd..00000000 --- a/features/fixtures/mazerunnerplainspring/build.gradle +++ /dev/null @@ -1,30 +0,0 @@ -plugins { - id "war" -} - -group 'com.bugsnag.mazerunnerplainspring' - -sourceCompatibility = '1.8' - -repositories { - mavenCentral() - maven { - url file('../libs').toURI() - } -} - -dependencies { - implementation("org.springframework:spring-webmvc:4.2.0.RELEASE") - implementation("javax.servlet:javax.servlet-api:3.1.0") - implementation("ch.qos.logback:logback-classic:1.2.3") - - implementation("com.fasterxml.jackson.core:jackson-annotations:2.9.1") - implementation("com.fasterxml.jackson.core:jackson-databind:2.9.1") - implementation("com.bugsnag:bugsnag:9.9.9-test") - implementation("com.bugsnag:bugsnag-spring:9.9.9-test") - implementation project(":scenarios") -} - -war { - archiveName = 'mazerunnerplainspring.war' -} \ No newline at end of file diff --git a/features/fixtures/mazerunnerplainspring/gradle/wrapper/gradle-wrapper.jar b/features/fixtures/mazerunnerplainspring/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 6b6ea3ab..00000000 Binary files a/features/fixtures/mazerunnerplainspring/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/features/fixtures/mazerunnerplainspring/gradle/wrapper/gradle-wrapper.properties b/features/fixtures/mazerunnerplainspring/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 66c44b07..00000000 --- a/features/fixtures/mazerunnerplainspring/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Mon Jan 29 14:52:51 GMT 2018 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-bin.zip diff --git a/features/fixtures/mazerunnerplainspring/gradlew b/features/fixtures/mazerunnerplainspring/gradlew deleted file mode 100755 index cccdd3d5..00000000 --- a/features/fixtures/mazerunnerplainspring/gradlew +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env sh - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/features/fixtures/mazerunnerplainspring/gradlew.bat b/features/fixtures/mazerunnerplainspring/gradlew.bat deleted file mode 100644 index e95643d6..00000000 --- a/features/fixtures/mazerunnerplainspring/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/AppConfig.java b/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/AppConfig.java deleted file mode 100644 index d6389828..00000000 --- a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/AppConfig.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.bugsnag.mazerunnerplainspring; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; -import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; -import org.springframework.scheduling.annotation.EnableAsync; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; - -@Configuration -@EnableWebMvc -@EnableScheduling -@EnableAsync -@ComponentScan(basePackages = "com.bugsnag.mazerunnerplainspring") -public class AppConfig { - @Bean - public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() { - return new PropertySourcesPlaceholderConfigurer(); - } -} \ No newline at end of file diff --git a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/AppInitializer.java b/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/AppInitializer.java deleted file mode 100644 index 2fd1cf0f..00000000 --- a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/AppInitializer.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.bugsnag.mazerunnerplainspring; - -import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; - -public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { - - @Override - protected Class[] getRootConfigClasses() { - return new Class[] { AppConfig.class }; - } - - @Override - protected Class[] getServletConfigClasses() { - return null; - } - - @Override - protected String[] getServletMappings() { - return new String[] { "/" }; - } - -} \ No newline at end of file diff --git a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/AsyncMethodService.java b/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/AsyncMethodService.java deleted file mode 100644 index f1d52269..00000000 --- a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/AsyncMethodService.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.bugsnag.mazerunnerplainspring; - -import com.bugsnag.Bugsnag; -import org.springframework.scheduling.annotation.Async; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; - -import java.util.concurrent.Future; - -@Service -public class AsyncMethodService { - - @Async - public void doSomethingAsync() { - - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "key1", "should be cleared from meta data"); - Bugsnag.clearThreadMetaData(); - Bugsnag.addThreadMetaData("thread", "key2", "should be included in meta data"); - - try { - Thread.sleep(100); - } catch (InterruptedException e) { - // ignore - } - - throw new RuntimeException("Unhandled exception from Async method"); - } -} diff --git a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/BugsnagAsyncConfig.java b/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/BugsnagAsyncConfig.java deleted file mode 100644 index d1b0e59e..00000000 --- a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/BugsnagAsyncConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.bugsnag.mazerunnerplainspring; - -import com.bugsnag.Bugsnag; -import com.bugsnag.BugsnagAsyncExceptionHandler; -import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.AsyncConfigurerSupport; - -@Configuration -public class BugsnagAsyncConfig extends AsyncConfigurerSupport { - @Autowired - private Bugsnag bugsnag; - - @Override - public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { - return new BugsnagAsyncExceptionHandler(bugsnag); - } -} diff --git a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/BugsnagConfig.java b/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/BugsnagConfig.java deleted file mode 100644 index cf5d52ca..00000000 --- a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/BugsnagConfig.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.bugsnag.mazerunnerplainspring; - -import com.bugsnag.Bugsnag; -import com.bugsnag.BugsnagSpringConfiguration; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.util.StringUtils; - -@Configuration -@Import(BugsnagSpringConfiguration.class) -public class BugsnagConfig { - - @Value("${BUGSNAG_API_KEY}") - private String bugsnagApiKey; - - @Value("${MAZERUNNER_BASE_URL}") - private String bugsnagEndpoint; - - @Value("${AUTO_CAPTURE_SESSIONS:false}") - private boolean autoCaptureSessions; - - @Bean - public Bugsnag bugsnag() { - Bugsnag bugsnag = new Bugsnag(bugsnagApiKey); - bugsnag.setEndpoints(bugsnagEndpoint + "notify", bugsnagEndpoint + "sessions"); - bugsnag.setAutoCaptureSessions(autoCaptureSessions); - bugsnag.setReleaseStage("production"); - bugsnag.setAppVersion("1.0.0"); - return bugsnag; - } -} diff --git a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/ScheduledTaskService.java b/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/ScheduledTaskService.java deleted file mode 100644 index 3574ff08..00000000 --- a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/ScheduledTaskService.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.bugsnag.mazerunnerplainspring; - -import com.bugsnag.Bugsnag; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; - -@Service -public class ScheduledTaskService { - - @Value("${RUN_SCHEDULED_TASK:false}") - private boolean throwException; - - private volatile boolean exceptionSent = false; - - @Scheduled(fixedDelay = 3000) - public void doSomething() { - if (throwException && !exceptionSent) { - - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "key1", "should be cleared from meta data"); - Bugsnag.clearThreadMetaData(); - Bugsnag.addThreadMetaData("thread", "key2", "should be included in meta data"); - - exceptionSent = true; - throw new RuntimeException("Unhandled exception from ScheduledTaskService"); - } - } -} diff --git a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/TestRestController.java b/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/TestRestController.java deleted file mode 100644 index 59496a2f..00000000 --- a/features/fixtures/mazerunnerplainspring/src/main/java/com.bugsnag.mazerunnerplainspring/TestRestController.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.bugsnag.mazerunnerplainspring; - -import com.bugsnag.Bugsnag; -import com.bugsnag.mazerunner.scenarios.Scenario; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; - -@RestController -public class TestRestController { - - private static final Logger LOGGER = LoggerFactory.getLogger(TestRestController.class); - - @Autowired - private Bugsnag bugsnag; - - @Autowired - private AsyncMethodService asyncMethodService; - - @RequestMapping("/") - public String ping() { - return "Plain Spring Fixture app ready for connections"; - } - - @RequestMapping("/send-unhandled-exception") - public void sendUnhandledException() { - throw new RuntimeException("Unhandled exception from TestRestController"); - } - - @RequestMapping("/add-session") - public void addSession() { - // A session should be automatically recorded by Bugsnag if automatic sessions are enabled - LOGGER.info("Starting a new session"); - - // Flush sessions now, otherwise need to wait for sessions to be automatically flushed - flushAllSessions(); - LOGGER.info("Flushed all sessions"); - } - - @RequestMapping("/run-async-task") - public void runAsyncTask() { - try { - asyncMethodService.doSomethingAsync(); - } catch (Exception ex) { - // This should not happen - LOGGER.info("Saw exception from async call"); - } - } - - @RequestMapping("/run-scenario/{scenario}") - public void runScenario(@PathVariable String scenario) { - try { - Class clz = Class.forName("com.bugsnag.mazerunner.scenarios." + scenario); - Constructor constructor = clz.getConstructors()[0]; - ((Scenario) constructor.newInstance(bugsnag)).run(); - } catch (Exception ex) { - LOGGER.error("Error getting scenario", ex); - } - } - - /** - * Flushes sessions from the Bugsnag object - */ - private void flushAllSessions() { - try { - Field field = bugsnag.getClass().getDeclaredField("sessionTracker"); - field.setAccessible(true); - Object sessionTracker = field.get(bugsnag); - - field = sessionTracker.getClass().getDeclaredField("enqueuedSessionCounts"); - field.setAccessible(true); - Collection sessionCounts = (Collection) field.get(sessionTracker); - - // Flush the sessions - Method method = sessionTracker.getClass().getDeclaredMethod("flushSessions", Date.class); - method.setAccessible(true); - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.MINUTE, 2); - method.invoke(sessionTracker, calendar.getTime()); - - // Wait until sessions are flushed - while (sessionCounts.size() > 0) { - Thread.sleep(1000); - } - } catch (Exception ex) { - LOGGER.error("failed to flush sessions", ex); - } - } -} diff --git a/features/fixtures/mazerunnerplainspring6/build.gradle b/features/fixtures/mazerunnerplainspring6/build.gradle.kts similarity index 50% rename from features/fixtures/mazerunnerplainspring6/build.gradle rename to features/fixtures/mazerunnerplainspring6/build.gradle.kts index d53ec39a..9b5bdefc 100644 --- a/features/fixtures/mazerunnerplainspring6/build.gradle +++ b/features/fixtures/mazerunnerplainspring6/build.gradle.kts @@ -1,28 +1,36 @@ plugins { - id "war" + war } -group 'com.bugsnag.mazerunnerplainspring' +group = "com.bugsnag.mazerunnerplainspring" + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} repositories { mavenCentral() maven { - url file('../libs').toURI() + url = file("../libs").toURI() } } dependencies { implementation("org.springframework:spring-webmvc:6.0.0") implementation("jakarta.servlet:jakarta.servlet-api:5.0.0") - implementation("ch.qos.logback:logback-classic:1.2.3") + implementation("ch.qos.logback:logback-classic:1.5.18") + implementation("org.codehaus.janino:janino:3.1.10") - implementation("com.fasterxml.jackson.core:jackson-annotations:2.9.1") - implementation("com.fasterxml.jackson.core:jackson-databind:2.9.1") + implementation("com.fasterxml.jackson.core:jackson-annotations:2.14.1") + implementation("com.fasterxml.jackson.core:jackson-databind:2.14.1") implementation("com.bugsnag:bugsnag:9.9.9-test") implementation("com.bugsnag:bugsnag-spring:9.9.9-test") - implementation project(":scenarios") + implementation(project(":scenarios")) +} + +tasks.named("war") { + archiveFileName.set("mazerunnerplainspring.war") } -war { - archiveName = 'mazerunnerplainspring.war' -} \ No newline at end of file diff --git a/features/fixtures/mazerunnerplainspring6/src/main/java/com.bugsnag.mazerunnerplainspring/AsyncMethodService.java b/features/fixtures/mazerunnerplainspring6/src/main/java/com.bugsnag.mazerunnerplainspring/AsyncMethodService.java index f1d52269..20c58073 100644 --- a/features/fixtures/mazerunnerplainspring6/src/main/java/com.bugsnag.mazerunnerplainspring/AsyncMethodService.java +++ b/features/fixtures/mazerunnerplainspring6/src/main/java/com.bugsnag.mazerunnerplainspring/AsyncMethodService.java @@ -13,10 +13,10 @@ public class AsyncMethodService { @Async public void doSomethingAsync() { - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "key1", "should be cleared from meta data"); - Bugsnag.clearThreadMetaData(); - Bugsnag.addThreadMetaData("thread", "key2", "should be included in meta data"); + // Add some thread metadata + Bugsnag.addThreadMetadata("thread", "key1", "should be cleared from metadata"); + Bugsnag.clearThreadMetadata(); + Bugsnag.addThreadMetadata("thread", "key2", "should be included in metadata"); try { Thread.sleep(100); diff --git a/features/fixtures/mazerunnerplainspring6/src/main/java/com.bugsnag.mazerunnerplainspring/ScheduledTaskService.java b/features/fixtures/mazerunnerplainspring6/src/main/java/com.bugsnag.mazerunnerplainspring/ScheduledTaskService.java index 3574ff08..dd9eb8d8 100644 --- a/features/fixtures/mazerunnerplainspring6/src/main/java/com.bugsnag.mazerunnerplainspring/ScheduledTaskService.java +++ b/features/fixtures/mazerunnerplainspring6/src/main/java/com.bugsnag.mazerunnerplainspring/ScheduledTaskService.java @@ -17,10 +17,10 @@ public class ScheduledTaskService { public void doSomething() { if (throwException && !exceptionSent) { - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "key1", "should be cleared from meta data"); - Bugsnag.clearThreadMetaData(); - Bugsnag.addThreadMetaData("thread", "key2", "should be included in meta data"); + // Add some thread metadata + Bugsnag.addThreadMetadata("thread", "key1", "should be cleared from metadata"); + Bugsnag.clearThreadMetadata(); + Bugsnag.addThreadMetadata("thread", "key2", "should be included in metadata"); exceptionSent = true; throw new RuntimeException("Unhandled exception from ScheduledTaskService"); diff --git a/features/fixtures/mazerunnerspringboot/build.gradle b/features/fixtures/mazerunnerspringboot/build.gradle deleted file mode 100644 index 65556010..00000000 --- a/features/fixtures/mazerunnerspringboot/build.gradle +++ /dev/null @@ -1,44 +0,0 @@ -buildscript { - ext { - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -group 'com.bugsnag.mazerunnerspringboot' -version '1.0-SNAPSHOT' - -sourceCompatibility = '1.8' - -repositories { - mavenCentral() - maven { - url file('../libs').toURI() - } -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter' - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'ch.qos.logback:logback-classic:1.2.3' - - implementation 'com.fasterxml.jackson.core:jackson-annotations:2.9.1' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.1' - implementation 'com.bugsnag:bugsnag:9.9.9-test' - implementation 'com.bugsnag:bugsnag-spring:9.9.9-test' - implementation project(":scenarios") - - // required for JDK 9 and above - implementation('javax.xml.bind:jaxb-api:2.3.0') - - testImplementation group: 'junit', name: 'junit', version: '4.13.2' -} \ No newline at end of file diff --git a/features/fixtures/mazerunnerspringboot/gradle/wrapper/gradle-wrapper.jar b/features/fixtures/mazerunnerspringboot/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 6b6ea3ab..00000000 Binary files a/features/fixtures/mazerunnerspringboot/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/features/fixtures/mazerunnerspringboot/gradle/wrapper/gradle-wrapper.properties b/features/fixtures/mazerunnerspringboot/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 66c44b07..00000000 --- a/features/fixtures/mazerunnerspringboot/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Mon Jan 29 14:52:51 GMT 2018 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-bin.zip diff --git a/features/fixtures/mazerunnerspringboot/gradlew b/features/fixtures/mazerunnerspringboot/gradlew deleted file mode 100755 index cccdd3d5..00000000 --- a/features/fixtures/mazerunnerspringboot/gradlew +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env sh - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/features/fixtures/mazerunnerspringboot/gradlew.bat b/features/fixtures/mazerunnerspringboot/gradlew.bat deleted file mode 100644 index e95643d6..00000000 --- a/features/fixtures/mazerunnerspringboot/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/AsyncMethodScenario.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/AsyncMethodScenario.java deleted file mode 100644 index a7425c16..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/AsyncMethodScenario.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.bugsnag.mazerunner.scenarios; - -import com.bugsnag.Bugsnag; -import org.springframework.web.client.RestTemplate; - -/** - * Causes an unhandled exception in an async method - */ -public class AsyncMethodScenario extends Scenario { - - public AsyncMethodScenario(Bugsnag bugsnag) { - super(bugsnag); - } - - @Override - public void run() { - - // Don't report any sessions during this test - disableSessionDelivery(); - - // The rest endpoint will run an async task to throw the exception - final String uri = "http://localhost:1234/run-async-task"; - - try { - RestTemplate restTemplate = new RestTemplate(); - restTemplate.getForObject(uri, String.class); - - // Wait for the async task to complete - Thread.sleep(2000); - } catch (Exception ex) { - // ignore - } - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/AsyncNotifyScenario.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/AsyncNotifyScenario.java deleted file mode 100644 index 2e1d3c1f..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/AsyncNotifyScenario.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.bugsnag.mazerunner.scenarios; - -import com.bugsnag.Bugsnag; -import org.springframework.web.client.RestTemplate; - -/** - * Notifies from an async method - */ -public class AsyncNotifyScenario extends Scenario { - - public AsyncNotifyScenario(Bugsnag bugsnag) { - super(bugsnag); - } - - @Override - public void run() { - - // Don't report any sessions during this test - disableSessionDelivery(); - - // The rest endpoint will run an async task to throw the exception - final String uri = "http://localhost:1234/notify-async-task"; - - try { - RestTemplate restTemplate = new RestTemplate(); - restTemplate.getForObject(uri, String.class); - - // Wait for the async task to complete - Thread.sleep(2000); - } catch (Exception ex) { - // ignore - } - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/AutoSessionScenario.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/AutoSessionScenario.java deleted file mode 100644 index 8058edd9..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/AutoSessionScenario.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.bugsnag.mazerunner.scenarios; - -import com.bugsnag.Bugsnag; -import org.springframework.web.client.RestTemplate; - -/** - * Causes an unhandled exception in the rest controller - */ -public class AutoSessionScenario extends Scenario { - - public AutoSessionScenario(Bugsnag bugsnag) { - super(bugsnag); - } - - @Override - public void run() { - bugsnag.setAutoCaptureSessions(true); - - final String uri = "http://localhost:1234/add-session"; - - try { - RestTemplate restTemplate = new RestTemplate(); - String result = restTemplate.getForObject(uri, String.class); - LOGGER.info("Completed auto session request: " + result); - Thread.sleep(2000); - } catch (Exception ex) { - LOGGER.error("Failed to complete request", ex); - } - - flushAllSessions(); - - try { - Thread.sleep(2000); - } catch (InterruptedException ex) { - ex.printStackTrace(); - } - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/RestControllerScenario.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/RestControllerScenario.java deleted file mode 100644 index c9ce5da6..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/RestControllerScenario.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.bugsnag.mazerunner.scenarios; - -import com.bugsnag.Bugsnag; -import org.springframework.web.client.RestTemplate; - -/** - * Causes an unhandled exception in the rest controller - */ -public class RestControllerScenario extends Scenario { - - public RestControllerScenario(Bugsnag bugsnag) { - super(bugsnag); - } - - @Override - public void run() { - // Don't report any sessions during this test - disableSessionDelivery(); - - final String uri = "http://localhost:1234/send-unhandled-exception"; - - try { - RestTemplate restTemplate = new RestTemplate(); - String result = restTemplate.getForObject(uri, String.class); - } catch (Exception ex) { - // ignore - } - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/ScheduledTaskExecutorScenario.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/ScheduledTaskExecutorScenario.java deleted file mode 100644 index 5dc877b2..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/ScheduledTaskExecutorScenario.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.bugsnag.mazerunner.scenarios; - -import com.bugsnag.Bugsnag; -import com.bugsnag.Report; -import com.bugsnag.callbacks.Callback; -import com.bugsnag.mazerunnerspringboot.ScheduledTaskExecutorService; -import java.util.Collection; - -public class ScheduledTaskExecutorScenario extends Scenario { - - public ScheduledTaskExecutorScenario(Bugsnag bugsnag) { - super(bugsnag); - } - - @Override - public void run() { - // Enable throwing an exception in the scheduled task - ScheduledTaskExecutorService.setSendException(); - - // Wait for the exception - try { - Thread.sleep(5000); - } catch (InterruptedException ex) { - // ignore - } - - final Collection threadnames = ScheduledTaskExecutorService.getThreadNames(); - bugsnag.notify(new RuntimeException("Whoops"), new Callback() { - @Override - public void beforeNotify(Report report) { - report.addToTab("executor", "multiThreaded", threadnames.size() > 1); - report.addToTab("executor", "names", threadnames); - } - }); - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/ScheduledTaskScenario.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/ScheduledTaskScenario.java deleted file mode 100644 index acf29628..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunner/scenarios/ScheduledTaskScenario.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.bugsnag.mazerunner.scenarios; - -import com.bugsnag.Bugsnag; -import com.bugsnag.mazerunnerspringboot.ScheduledTaskService; - -/** - * Causes an unhandled exception in a scheduled task - */ -public class ScheduledTaskScenario extends Scenario { - - public ScheduledTaskScenario(Bugsnag bugsnag) { - super(bugsnag); - } - - @Override - public void run() { - // Enable throwing an exception in the scheduled task - ScheduledTaskService.setThrowException(); - - // Wait for the exception - try { - Thread.sleep(5000); - } catch (InterruptedException ex) { - // ignore - } - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/Application.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/Application.java deleted file mode 100644 index aa57b959..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/Application.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.bugsnag.mazerunnerspringboot; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.scheduling.annotation.EnableAsync; -import org.springframework.scheduling.annotation.EnableScheduling; - -/** - * Kicks off the Spring Boot application. - */ -@SpringBootApplication -@EnableScheduling -@EnableAsync -public class Application { - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/AsyncMethodService.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/AsyncMethodService.java deleted file mode 100644 index 5e0593a0..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/AsyncMethodService.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.bugsnag.mazerunnerspringboot; - -import com.bugsnag.Bugsnag; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; - -@Service -public class AsyncMethodService { - - @Autowired - Bugsnag bugsnag; - - @Async - public void doSomethingAsync() { - - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "key1", "should be cleared from meta data"); - Bugsnag.clearThreadMetaData(); - Bugsnag.addThreadMetaData("thread", "key2", "should be included in meta data"); - - try { - Thread.sleep(100); - } catch (InterruptedException ex) { - // ignore - } - - throw new RuntimeException("Unhandled exception from Async method"); - } - - @Async - public void notifyAsync() { - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "inAsyncMethod", "meta data from async method"); - - bugsnag.notify(new RuntimeException("test from async")); - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/BugsnagAsyncConfig.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/BugsnagAsyncConfig.java deleted file mode 100644 index 3c05e2a6..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/BugsnagAsyncConfig.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.bugsnag.mazerunnerspringboot; - -import com.bugsnag.Bugsnag; -import com.bugsnag.BugsnagAsyncExceptionHandler; -import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.AsyncConfigurerSupport; -import org.springframework.scheduling.annotation.EnableScheduling; - -@Configuration -@EnableScheduling -public class BugsnagAsyncConfig extends AsyncConfigurerSupport { - @Autowired - private Bugsnag bugsnag; - - @Override - public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { - return new BugsnagAsyncExceptionHandler(bugsnag); - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/Config.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/Config.java deleted file mode 100644 index 35b7d45d..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/Config.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.bugsnag.mazerunnerspringboot; - -import com.bugsnag.Bugsnag; -import com.bugsnag.BugsnagSpringConfiguration; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -@Configuration -@Import(BugsnagSpringConfiguration.class) -public class Config { - - @Value("${BUGSNAG_API_KEY}") - private String bugsnagApiKey; - - @Value("${MAZERUNNER_BASE_URL}") - private String bugsnagEndpoint; - - @Bean - public Bugsnag bugsnag() { - Bugsnag bugsnag = new Bugsnag(bugsnagApiKey); - bugsnag.setEndpoints(bugsnagEndpoint + "notify", bugsnagEndpoint + "sessions"); - bugsnag.setReleaseStage("production"); - bugsnag.setAppVersion("1.0.0"); - return bugsnag; - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskConfig.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskConfig.java deleted file mode 100644 index 532bbc77..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskConfig.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.bugsnag.mazerunnerspringboot; - -import com.bugsnag.Bugsnag; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.scheduling.annotation.EnableScheduling; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -@Configuration -@EnableScheduling -public class ScheduledTaskConfig { - - @ConditionalOnProperty(name = "scheduled_executor_service_bean", havingValue = "true") - @Bean - public Executor taskScheduler() { - return Executors.newScheduledThreadPool(4); - } - - @ConditionalOnProperty(name = "other_scheduled_executor_service_bean", havingValue = "true") - @Bean - public Executor otherTaskScheduler() { - return Executors.newScheduledThreadPool(2); - } - - @ConditionalOnProperty(name = "custom_task_scheduler_bean", havingValue = "true") - @Bean - public TaskScheduler customTaskScheduler() { - ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); - scheduler.setPoolSize(4); - return scheduler; - } - - @ConditionalOnProperty(name = "second_task_scheduler_bean", havingValue = "true") - @Bean(name = "taskScheduler") - public TaskScheduler secondTaskScheduler() { - ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); - scheduler.setPoolSize(2); - return scheduler; - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskExecutorService.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskExecutorService.java deleted file mode 100644 index 99c3a988..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskExecutorService.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.bugsnag.mazerunnerspringboot; - -import com.bugsnag.Bugsnag; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.springframework.beans.factory.annotation.Autowired; -import java.util.HashSet; -import java.util.Set; -import java.util.Collection; - -@Service -public class ScheduledTaskExecutorService { - - @Autowired - private Bugsnag bugsnag; - - private final Set threadNames = new HashSet(); - - private volatile boolean sendException = false; - - private static ScheduledTaskExecutorService instance; - - public ScheduledTaskExecutorService() { - instance = this; - } - - public static void setSendException() { - instance.sendException = true; - } - - public static Collection getThreadNames() { - return new HashSet<>(instance.threadNames); - } - - @Scheduled(fixedRate = 100) - public void doSomething() { - if (sendException) { - threadNames.add(Thread.currentThread().getName()); - } - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskService.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskService.java deleted file mode 100644 index 93cb9d6c..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskService.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.bugsnag.mazerunnerspringboot; - -import com.bugsnag.Bugsnag; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; - -@Service -public class ScheduledTaskService { - - private volatile boolean throwException = false; - - private static ScheduledTaskService instance; - - public ScheduledTaskService() { - instance = this; - } - - public static void setThrowException() { - instance.throwException = true; - } - - @Scheduled(fixedDelay = 3000) - public void doSomething() { - if (throwException) { - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "key1", "should be cleared from meta data"); - Bugsnag.clearThreadMetaData(); - Bugsnag.addThreadMetaData("thread", "key2", "should be included in meta data"); - - throw new RuntimeException("Unhandled exception from ScheduledTaskService"); - } - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/TestCaseRunner.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/TestCaseRunner.java deleted file mode 100644 index 82839269..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/TestCaseRunner.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.bugsnag.mazerunnerspringboot; - -import com.bugsnag.Bugsnag; -import com.bugsnag.mazerunner.scenarios.Scenario; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.CommandLineRunner; -import org.springframework.boot.ExitCodeGenerator; -import org.springframework.boot.SpringApplication; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.stereotype.Component; - -import java.lang.reflect.Constructor; - -@Component -public class TestCaseRunner implements CommandLineRunner, ApplicationContextAware { - - private static final Logger LOGGER = LoggerFactory.getLogger(TestCaseRunner.class); - - private ApplicationContext ctx; - - @Autowired - private Bugsnag bugsnag; - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - ctx = applicationContext; - } - - @Override - public void run(String... args) { - // Create and run the test case - LOGGER.info("Creating test case"); - String type = System.getenv("EVENT_TYPE"); - Scenario scenario = testCaseForName(type); - if (scenario != null) { - LOGGER.info("running test case " + type); - scenario.run(); - } else { - LOGGER.error("No test case found for " + type); - } - - // Exit the application - LOGGER.info("Exiting spring"); - System.exit(SpringApplication.exit(ctx, (ExitCodeGenerator) new ExitCodeGenerator() { - @Override - public int getExitCode() { - return 0; - } - })); - } - - private Scenario testCaseForName(String eventType) { - try { - Class clz = Class.forName("com.bugsnag.mazerunner.scenarios." + eventType); - Constructor constructor = clz.getConstructors()[0]; - return (Scenario) constructor.newInstance(bugsnag); - } catch (Exception ex) { - LOGGER.error("Error getting scenario", ex); - return null; - } - } -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/TestRestController.java b/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/TestRestController.java deleted file mode 100644 index e35c0524..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/java/com/bugsnag/mazerunnerspringboot/TestRestController.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.bugsnag.mazerunnerspringboot; - -import com.bugsnag.Bugsnag; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class TestRestController { - - private static final Logger LOGGER = LoggerFactory.getLogger(TestRestController.class); - - @Autowired - Bugsnag bugsnag; - - @Autowired - private AsyncMethodService asyncMethodService; - - private static TestRestController instance; - - public TestRestController() { - instance = this; - } - - public static Bugsnag getBugsnag() { - return instance.bugsnag; - } - - @RequestMapping("/send-unhandled-exception") - public String sendUnhandledException() { - throw new RuntimeException("Unhandled exception from TestRestController"); - } - - @RequestMapping("/add-session") - public String addSession() { - // A session should be automatically recorded by Bugsnag if automatic sessions are enabled - LOGGER.info("Starting a new session"); - return ""; - } - - @RequestMapping("/run-async-task") - public String runAsyncTask() { - try { - asyncMethodService.doSomethingAsync(); - } catch (Exception ex) { - // This should not happen - LOGGER.info("Saw exception from async call"); - } - - return ""; - } - - @RequestMapping("/notify-async-task") - public String notifyAsyncTask() { - - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "controllerMethod", "meta data from controller method"); - - // Notify before calling the async method - bugsnag.notify(new RuntimeException("test from before async")); - - // Call the async method (also notifies) - asyncMethodService.notifyAsync(); - - return ""; - } - -} diff --git a/features/fixtures/mazerunnerspringboot/src/main/resources/application.properties b/features/fixtures/mazerunnerspringboot/src/main/resources/application.properties deleted file mode 100644 index 7e96c7f7..00000000 --- a/features/fixtures/mazerunnerspringboot/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ -server.port=1234 diff --git a/features/fixtures/mazerunnerspringboot3/build.gradle b/features/fixtures/mazerunnerspringboot3/build.gradle index 77963142..4a10e93b 100644 --- a/features/fixtures/mazerunnerspringboot3/build.gradle +++ b/features/fixtures/mazerunnerspringboot3/build.gradle @@ -1,6 +1,6 @@ buildscript { ext { - springBootVersion = '3.0.0' + springBootVersion = '3.5.6' } repositories { mavenCentral() @@ -17,6 +17,12 @@ apply plugin: 'io.spring.dependency-management' group 'com.bugsnag.mazerunnerspringboot3' version '1.0-SNAPSHOT' +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + repositories { mavenCentral() maven { @@ -27,13 +33,15 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'ch.qos.logback:logback-classic:1.5.18' + implementation 'org.codehaus.janino:janino:3.1.10' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.14.1' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.1' implementation 'com.bugsnag:bugsnag:9.9.9-test' implementation 'com.bugsnag:bugsnag-spring:9.9.9-test' implementation project(":scenarios") - // required for JDK 9 and above - implementation('javax.xml.bind:jaxb-api:2.3.0') testImplementation group: 'junit', name: 'junit', version: '4.13.2' } \ No newline at end of file diff --git a/features/fixtures/mazerunnerspringboot3/build.gradle.kts b/features/fixtures/mazerunnerspringboot3/build.gradle.kts new file mode 100644 index 00000000..f63817d9 --- /dev/null +++ b/features/fixtures/mazerunnerspringboot3/build.gradle.kts @@ -0,0 +1,37 @@ +plugins { + java + id("org.springframework.boot") version "3.5.6" + id("io.spring.dependency-management") version "1.1.0" +} + +group = "com.bugsnag.mazerunnerspringboot3" +version = "1.0-SNAPSHOT" + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +repositories { + mavenCentral() + maven { + url = file("../libs").toURI() + } +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter") + implementation("org.springframework.boot:spring-boot-starter-web") + implementation("ch.qos.logback:logback-classic:1.5.18") + implementation("org.codehaus.janino:janino:3.1.10") + + implementation("com.fasterxml.jackson.core:jackson-annotations:2.14.1") + implementation("com.fasterxml.jackson.core:jackson-databind:2.14.1") + implementation("com.bugsnag:bugsnag:9.9.9-test") + implementation("com.bugsnag:bugsnag-spring:9.9.9-test") + implementation(project(":scenarios")) + + testImplementation("junit:junit:4.13.2") +} + diff --git a/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/AsyncMethodService.java b/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/AsyncMethodService.java index 5e0593a0..41ed6727 100644 --- a/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/AsyncMethodService.java +++ b/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/AsyncMethodService.java @@ -15,10 +15,10 @@ public class AsyncMethodService { @Async public void doSomethingAsync() { - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "key1", "should be cleared from meta data"); - Bugsnag.clearThreadMetaData(); - Bugsnag.addThreadMetaData("thread", "key2", "should be included in meta data"); + // Add some thread metadata + Bugsnag.addThreadMetadata("thread", "key1", "should be cleared from metadata"); + Bugsnag.clearThreadMetadata(); + Bugsnag.addThreadMetadata("thread", "key2", "should be included in metadata"); try { Thread.sleep(100); @@ -32,7 +32,7 @@ public void doSomethingAsync() { @Async public void notifyAsync() { // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "inAsyncMethod", "meta data from async method"); + Bugsnag.addThreadMetadata("thread", "inAsyncMethod", "meta data from async method"); bugsnag.notify(new RuntimeException("test from async")); } diff --git a/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskConfig.java b/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskConfig.java index 532bbc77..febf74cb 100644 --- a/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskConfig.java +++ b/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskConfig.java @@ -6,39 +6,39 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.scheduling.annotation.EnableScheduling; -import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; @Configuration -@EnableScheduling public class ScheduledTaskConfig { @ConditionalOnProperty(name = "scheduled_executor_service_bean", havingValue = "true") - @Bean - public Executor taskScheduler() { + @Bean(name = "taskScheduler") + public ScheduledExecutorService taskScheduler() { return Executors.newScheduledThreadPool(4); } @ConditionalOnProperty(name = "other_scheduled_executor_service_bean", havingValue = "true") @Bean - public Executor otherTaskScheduler() { + public ScheduledExecutorService otherTaskScheduler() { return Executors.newScheduledThreadPool(2); } @ConditionalOnProperty(name = "custom_task_scheduler_bean", havingValue = "true") - @Bean + @Bean(name = "taskScheduler") public TaskScheduler customTaskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(4); + scheduler.initialize(); return scheduler; } @ConditionalOnProperty(name = "second_task_scheduler_bean", havingValue = "true") - @Bean(name = "taskScheduler") + @Bean(name = "secondTaskScheduler") public TaskScheduler secondTaskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(2); + scheduler.initialize(); return scheduler; } } diff --git a/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskService.java b/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskService.java index 93cb9d6c..5889e122 100644 --- a/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskService.java +++ b/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/ScheduledTaskService.java @@ -22,12 +22,16 @@ public static void setThrowException() { @Scheduled(fixedDelay = 3000) public void doSomething() { if (throwException) { - // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "key1", "should be cleared from meta data"); - Bugsnag.clearThreadMetaData(); - Bugsnag.addThreadMetaData("thread", "key2", "should be included in meta data"); + // Reset the flag so we only throw once + throwException = false; + + // Add some thread metadata + Bugsnag.addThreadMetadata("thread", "key1", "should be cleared from metadata"); + Bugsnag.clearThreadMetadata(); + Bugsnag.addThreadMetadata("thread", "key2", "should be included in metadata"); throw new RuntimeException("Unhandled exception from ScheduledTaskService"); } } } + diff --git a/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/TestRestController.java b/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/TestRestController.java index e35c0524..c8667ffb 100644 --- a/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/TestRestController.java +++ b/features/fixtures/mazerunnerspringboot3/src/main/java/com/bugsnag/mazerunnerspringboot/TestRestController.java @@ -57,7 +57,7 @@ public String runAsyncTask() { public String notifyAsyncTask() { // Add some thread meta data - Bugsnag.addThreadMetaData("thread", "controllerMethod", "meta data from controller method"); + Bugsnag.addThreadMetadata("thread", "controllerMethod", "meta data from controller method"); // Notify before calling the async method bugsnag.notify(new RuntimeException("test from before async")); diff --git a/features/fixtures/scenarios/build.gradle b/features/fixtures/scenarios/build.gradle deleted file mode 100644 index c7074b7b..00000000 --- a/features/fixtures/scenarios/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -apply plugin: 'java' - -group 'com.bugsnag.mazerunner' - -sourceCompatibility = '1.8' - -repositories { - mavenCentral() - maven { - url file('../libs').toURI() - } -} - -dependencies { - implementation("ch.qos.logback:logback-classic:1.2.3") - implementation("com.bugsnag:bugsnag:9.9.9-test") -} - diff --git a/features/fixtures/scenarios/build.gradle.kts b/features/fixtures/scenarios/build.gradle.kts new file mode 100644 index 00000000..8057ca9d --- /dev/null +++ b/features/fixtures/scenarios/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + java +} + +group = "com.bugsnag.mazerunner" + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +repositories { + mavenCentral() + maven { + url = file("../libs").toURI() + } +} + +dependencies { + implementation("ch.qos.logback:logback-classic:1.5.18") + implementation("org.codehaus.janino:janino:3.1.10") + implementation("com.bugsnag:bugsnag:9.9.9-test") +} + diff --git a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ArrayNotifyReleaseStageScenario.java b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ArrayNotifyReleaseStageScenario.java index 9aa0ac58..b6225eec 100644 --- a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ArrayNotifyReleaseStageScenario.java +++ b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ArrayNotifyReleaseStageScenario.java @@ -14,7 +14,7 @@ public ArrayNotifyReleaseStageScenario(Bugsnag bugsnag) { @Override public void run() { bugsnag.setReleaseStage("prod"); - bugsnag.setNotifyReleaseStages("dev", "prod"); + bugsnag.setEnabledReleaseStages("dev", "prod"); bugsnag.notify(generateException()); } } diff --git a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/AutoFilterScenario.java b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/AutoRedactScenario.java similarity index 83% rename from features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/AutoFilterScenario.java rename to features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/AutoRedactScenario.java index 27b3de61..bfafab71 100644 --- a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/AutoFilterScenario.java +++ b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/AutoRedactScenario.java @@ -5,11 +5,11 @@ import com.bugsnag.callbacks.Callback; /** - * Sends a handled exception to Bugsnag, which contains metadata that should be filtered + * Sends a handled exception to Bugsnag, which contains metadata that should be redacted */ -public class AutoFilterScenario extends Scenario { +public class AutoRedactScenario extends Scenario { - public AutoFilterScenario(Bugsnag bugsnag) { + public AutoRedactScenario(Bugsnag bugsnag) { super(bugsnag); } diff --git a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/IgnoredExceptionScenario.java b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/IgnoredExceptionScenario.java index f2612590..ef0dfc3d 100644 --- a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/IgnoredExceptionScenario.java +++ b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/IgnoredExceptionScenario.java @@ -15,7 +15,7 @@ public IgnoredExceptionScenario(Bugsnag bugsnag) { @Override public void run() { - bugsnag.setIgnoreClasses("java.lang.RuntimeException"); + bugsnag.setDiscardClasses("java.lang.RuntimeException"); bugsnag.notify(new RuntimeException("Should never appear")); } diff --git a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/InsideReleaseStageScenario.java b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/InsideReleaseStageScenario.java index fbe7d13f..9eb129db 100644 --- a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/InsideReleaseStageScenario.java +++ b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/InsideReleaseStageScenario.java @@ -14,7 +14,7 @@ public InsideReleaseStageScenario(Bugsnag bugsnag) { @Override public void run() { bugsnag.setReleaseStage("prod"); - bugsnag.setNotifyReleaseStages("prod"); + bugsnag.setEnabledReleaseStages("prod"); bugsnag.notify(generateException()); } } diff --git a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/LogbackMetaDataScenario.java b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/LogbackMetadataScenario.java similarity index 79% rename from features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/LogbackMetaDataScenario.java rename to features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/LogbackMetadataScenario.java index 698bee5a..37bd1ad7 100644 --- a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/LogbackMetaDataScenario.java +++ b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/LogbackMetadataScenario.java @@ -9,13 +9,13 @@ import org.slf4j.LoggerFactory; /** - * Sends an exception to Bugsnag with custom meta data using the logback appender + * Sends an exception to Bugsnag with custom metadata using the logback appender */ -public class LogbackMetaDataScenario extends Scenario { +public class LogbackMetadataScenario extends Scenario { - private static final Logger LOGGER = LoggerFactory.getLogger(LogbackMetaDataScenario.class); + private static final Logger LOGGER = LoggerFactory.getLogger(LogbackMetadataScenario.class); - public LogbackMetaDataScenario(Bugsnag bugsnag) { + public LogbackMetadataScenario(Bugsnag bugsnag) { super(bugsnag); } diff --git a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/LogbackThreadMetaDataScenario.java b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/LogbackThreadMetadataScenario.java similarity index 62% rename from features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/LogbackThreadMetaDataScenario.java rename to features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/LogbackThreadMetadataScenario.java index b2ea7d40..04c34da5 100644 --- a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/LogbackThreadMetaDataScenario.java +++ b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/LogbackThreadMetadataScenario.java @@ -7,27 +7,27 @@ import org.slf4j.LoggerFactory; /** - * Sends an exception to Bugsnag with custom meta data using the logback appender + * Sends an exception to Bugsnag with custom metadata using the logback appender */ -public class LogbackThreadMetaDataScenario extends Scenario { +public class LogbackThreadMetadataScenario extends Scenario { private static final Logger LOGGER = - LoggerFactory.getLogger(LogbackThreadMetaDataScenario.class); + LoggerFactory.getLogger(LogbackThreadMetadataScenario.class); - public LogbackThreadMetaDataScenario(Bugsnag bugsnag) { + public LogbackThreadMetadataScenario(Bugsnag bugsnag) { super(bugsnag); } @Override public void run() { - Bugsnag.addThreadMetaData("thread", "foo", "threadvalue1"); - Bugsnag.addThreadMetaData("thread", "bar", "threadvalue2"); + Bugsnag.addThreadMetadata("thread", "foo", "threadvalue1"); + Bugsnag.addThreadMetadata("thread", "bar", "threadvalue2"); // Thread metadata on a different thread should not get added Thread t1 = new Thread(new Runnable() { @Override public void run() { - Bugsnag.addThreadMetaData("Custom", "something", "This should not be on the report"); + Bugsnag.addThreadMetadata("Custom", "something", "This should not be on the report"); } }); diff --git a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ManualFilterScenario.java b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ManualRedactScenario.java similarity index 78% rename from features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ManualFilterScenario.java rename to features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ManualRedactScenario.java index 7ae38999..22685510 100644 --- a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ManualFilterScenario.java +++ b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ManualRedactScenario.java @@ -5,18 +5,18 @@ import com.bugsnag.callbacks.Callback; /** - * Sends a handled exception to Bugsnag, which contains metadata that should be filtered + * Sends a handled exception to Bugsnag, which contains metadata that should be redacted */ -public class ManualFilterScenario extends Scenario { +public class ManualRedactScenario extends Scenario { - public ManualFilterScenario(Bugsnag bugsnag) { + public ManualRedactScenario(Bugsnag bugsnag) { super(bugsnag); } @Override public void run() { - bugsnag.setFilters("foo"); + bugsnag.setRedactedKeys("foo"); bugsnag.notify(generateException(), new Callback() { @Override diff --git a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/MetaDataScenario.java b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/MetadataScenario.java similarity index 84% rename from features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/MetaDataScenario.java rename to features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/MetadataScenario.java index 63f2616a..e639c540 100644 --- a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/MetaDataScenario.java +++ b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/MetadataScenario.java @@ -7,9 +7,9 @@ /** * Sends a handled exception to Bugsnag, which includes custom metadata */ -public class MetaDataScenario extends Scenario { +public class MetadataScenario extends Scenario { - public MetaDataScenario(Bugsnag bugsnag) { + public MetadataScenario(Bugsnag bugsnag) { super(bugsnag); } diff --git a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/NullNotifyReleaseStageScenario.java b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/NullNotifyReleaseStageScenario.java index af4338b0..1d0e6255 100644 --- a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/NullNotifyReleaseStageScenario.java +++ b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/NullNotifyReleaseStageScenario.java @@ -3,7 +3,8 @@ import com.bugsnag.Bugsnag; /** - * Attempts to send a handled exception to Bugsnag, when the notifyReleaseStages is null. + * Attempts to send a handled exception to Bugsnag, when the + * enabledReleaseStages is null. */ public class NullNotifyReleaseStageScenario extends Scenario { diff --git a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/NullReleaseStageScenario.java b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/NullReleaseStageScenario.java index ae4b2c1f..7875c84d 100644 --- a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/NullReleaseStageScenario.java +++ b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/NullReleaseStageScenario.java @@ -14,7 +14,7 @@ public NullReleaseStageScenario(Bugsnag bugsnag) { @Override public void run() { bugsnag.setReleaseStage(null); - bugsnag.setNotifyReleaseStages("dev"); + bugsnag.setEnabledReleaseStages("dev"); bugsnag.notify(generateException()); } } diff --git a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/OutsideReleaseStageScenario.java b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/OutsideReleaseStageScenario.java index bd35ee73..efc8103d 100644 --- a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/OutsideReleaseStageScenario.java +++ b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/OutsideReleaseStageScenario.java @@ -15,7 +15,7 @@ public OutsideReleaseStageScenario(Bugsnag bugsnag) { @Override public void run() { bugsnag.setReleaseStage("prod"); - bugsnag.setNotifyReleaseStages("dev"); + bugsnag.setEnabledReleaseStages("dev"); bugsnag.notify(generateException()); } } diff --git a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ThreadMetaDataScenario.java b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ThreadMetadataScenario.java similarity index 79% rename from features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ThreadMetaDataScenario.java rename to features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ThreadMetadataScenario.java index 8a6a5c35..254718fa 100644 --- a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ThreadMetaDataScenario.java +++ b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/ThreadMetadataScenario.java @@ -5,11 +5,11 @@ import com.bugsnag.Report; /** - * Sends an exception to Bugsnag with custom meta data on the thread + * Sends an exception to Bugsnag with custom metadata on the thread */ -public class ThreadMetaDataScenario extends Scenario { +public class ThreadMetadataScenario extends Scenario { - public ThreadMetaDataScenario(Bugsnag bugsnag) { + public ThreadMetadataScenario(Bugsnag bugsnag) { super(bugsnag); } @@ -25,14 +25,14 @@ public void beforeNotify(Report report) { }); // Thread metadata should merge with global metadata and overwrite when duplicate key - Bugsnag.addThreadMetaData("Custom", "foo", "Thread value"); - Bugsnag.addThreadMetaData("Custom", "bar", "Thread value to be overwritten"); + Bugsnag.addThreadMetadata("Custom", "foo", "Thread value"); + Bugsnag.addThreadMetadata("Custom", "bar", "Thread value to be overwritten"); // Thread metadata on a different thread should not get added Thread t1 = new Thread(new Runnable() { @Override public void run() { - Bugsnag.addThreadMetaData("Custom", "something", "This should not be on the report"); + Bugsnag.addThreadMetadata("Custom", "something", "This should not be on the report"); } }); diff --git a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/UnhandledThreadMetaDataScenario.java b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/UnhandledThreadMetadataScenario.java similarity index 74% rename from features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/UnhandledThreadMetaDataScenario.java rename to features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/UnhandledThreadMetadataScenario.java index 1d8c4a45..c8c3dbba 100644 --- a/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/UnhandledThreadMetaDataScenario.java +++ b/features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/UnhandledThreadMetadataScenario.java @@ -5,11 +5,11 @@ import com.bugsnag.Report; /** - * Sends an unhandled exception to Bugsnag with custom meta data on the thread + * Sends an unhandled exception to Bugsnag with custom metadata on the thread */ -public class UnhandledThreadMetaDataScenario extends Scenario { +public class UnhandledThreadMetadataScenario extends Scenario { - public UnhandledThreadMetaDataScenario(Bugsnag bugsnag) { + public UnhandledThreadMetadataScenario(Bugsnag bugsnag) { super(bugsnag); } @@ -28,7 +28,7 @@ public void beforeNotify(Report report) { Thread t1 = new Thread(new Runnable() { @Override public void run() { - Bugsnag.addThreadMetaData("Custom", "something", "This should not be on the report"); + Bugsnag.addThreadMetadata("Custom", "something", "This should not be on the report"); } }); t1.start(); @@ -43,9 +43,9 @@ public void run() { @Override public void run() { // Thread metadata should merge with global metadata and overwrite when duplicate key - Bugsnag.addThreadMetaData("Custom", "foo", "Thread value 1"); - Bugsnag.addThreadMetaData("Custom", "bar", "Thread value 2"); - throw new RuntimeException("UnhandledThreadMetaDataScenario"); + Bugsnag.addThreadMetadata("Custom", "foo", "Thread value 1"); + Bugsnag.addThreadMetadata("Custom", "bar", "Thread value 2"); + throw new RuntimeException("UnhandledThreadMetadataScenario"); } }); t2.start(); diff --git a/features/fixtures/settings.gradle b/features/fixtures/settings.gradle deleted file mode 100644 index 3a78b3ca..00000000 --- a/features/fixtures/settings.gradle +++ /dev/null @@ -1,13 +0,0 @@ -include ':mazerunner', - ':mazerunnerplainspring', - ':mazerunnerspringboot', - ':scenarios' - -try { - if (JavaVersion.current() >= JavaVersion.VERSION_17) { - include ':mazerunnerspringboot3', - ':mazerunnerplainspring6' - } -} catch (ignored) { - // ignore any errors, they are almost always Gradle / JVM version issues -} diff --git a/features/fixtures/settings.gradle.kts b/features/fixtures/settings.gradle.kts new file mode 100644 index 00000000..31c0edab --- /dev/null +++ b/features/fixtures/settings.gradle.kts @@ -0,0 +1,5 @@ +include(":mazerunner") +include(":scenarios") +include(":mazerunnerspringboot3") +include(":mazerunnerplainspring6") + diff --git a/features/meta_data.feature b/features/meta_data.feature index 7d268c5b..a77afff2 100644 --- a/features/meta_data.feature +++ b/features/meta_data.feature @@ -1,24 +1,24 @@ Feature: Reporting metadata Scenario: Sends a handled exception which includes custom metadata added in a notify callback - When I run "MetaDataScenario" with the defaults + When I run "MetadataScenario" with the defaults And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier And the event "metaData.Custom.foo" equals "Hello World!" Scenario: Sends a handled exception which includes custom metadata added in a notify callback for Spring Boot app - When I run spring boot "MetaDataScenario" with the defaults + When I run spring boot "MetadataScenario" with the defaults And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier And the event "metaData.Custom.foo" equals "Hello World!" Scenario: Sends a handled exception which includes custom metadata added in a notify callback for plain Spring app - When I run plain Spring "MetaDataScenario" with the defaults + When I run plain Spring "MetadataScenario" with the defaults And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier And the event "metaData.Custom.foo" equals "Hello World!" -Scenario: Test logback appender with meta data in the config file +Scenario: Test logback appender with metadata in the config file When I run "LogbackScenario" with logback config "meta_data_config.xml" And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier @@ -27,8 +27,8 @@ Scenario: Test logback appender with meta data in the config file And the event "metaData.configTab.foo" equals "tabValue1" And the event "metaData.configTab.bar" equals "tabValue2" -Scenario: Test logback appender with thread meta data - When I run "LogbackThreadMetaDataScenario" with logback config "basic_config.xml" +Scenario: Test logback appender with thread metadata + When I run "LogbackThreadMetadataScenario" with logback config "basic_config.xml" And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier And the error payload field "events" is an array with 1 elements @@ -36,8 +36,8 @@ Scenario: Test logback appender with thread meta data And the event "metaData.thread.foo" equals "threadvalue1" And the event "metaData.thread.bar" equals "threadvalue2" -Scenario: Test logback appender with meta data in a callback - When I run "LogbackMetaDataScenario" with logback config "basic_config.xml" +Scenario: Test logback appender with metadata in a callback + When I run "LogbackMetadataScenario" with logback config "basic_config.xml" And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier And the error payload field "events" is an array with 1 elements @@ -46,7 +46,7 @@ Scenario: Test logback appender with meta data in a callback And the event "metaData.custom.foo" equals "hunter2" And the event "metaData.custom.bar" equals "hunter2" -Scenario: Test logback appender with meta data from the MDC +Scenario: Test logback appender with metadata from the MDC When I run "LogbackMDCScenario" with logback config "basic_config.xml" And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier @@ -55,8 +55,8 @@ Scenario: Test logback appender with meta data from the MDC And the event "metaData.Context.foo" equals "hunter2" And the event "metaData.Context.bar" equals "hunter2" -Scenario: Test thread meta data - When I run "ThreadMetaDataScenario" with the defaults +Scenario: Test thread metadata + When I run "ThreadMetadataScenario" with the defaults And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier And the error payload field "events" is an array with 1 elements @@ -66,8 +66,8 @@ Scenario: Test thread meta data And the event "metaData.Custom.bar" equals "Hello World!" And the event "metaData.Custom.something" is null -Scenario: Test thread meta data for Spring Boot app - When I run spring boot "ThreadMetaDataScenario" with the defaults +Scenario: Test thread metadata for Spring Boot app + When I run spring boot "ThreadMetadataScenario" with the defaults And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier And the error payload field "events" is an array with 1 elements @@ -77,8 +77,8 @@ Scenario: Test thread meta data for Spring Boot app And the event "metaData.Custom.bar" equals "Hello World!" And the event "metaData.Custom.something" is null -Scenario: Test thread meta data for plain Spring app - When I run plain Spring "ThreadMetaDataScenario" with the defaults +Scenario: Test thread metadata for plain Spring app + When I run plain Spring "ThreadMetadataScenario" with the defaults And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier And the error payload field "events" is an array with 1 elements @@ -88,8 +88,8 @@ Scenario: Test thread meta data for plain Spring app And the event "metaData.Custom.bar" equals "Hello World!" And the event "metaData.Custom.something" is null -Scenario: Test unhandled thread meta data - When I run "UnhandledThreadMetaDataScenario" with the defaults +Scenario: Test unhandled thread metadata + When I run "UnhandledThreadMetadataScenario" with the defaults And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier And the error payload field "events" is an array with 1 elements @@ -99,8 +99,8 @@ Scenario: Test unhandled thread meta data And the event "metaData.Custom.bar" equals "Thread value 2" And the event "metaData.Custom.something" is null -Scenario: Test unhandled thread meta data for Spring Boot app - When I run spring boot "UnhandledThreadMetaDataScenario" with the defaults +Scenario: Test unhandled thread metadata for Spring Boot app + When I run spring boot "UnhandledThreadMetadataScenario" with the defaults And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier And the error payload field "events" is an array with 1 elements @@ -110,8 +110,8 @@ Scenario: Test unhandled thread meta data for Spring Boot app And the event "metaData.Custom.bar" equals "Thread value 2" And the event "metaData.Custom.something" is null -Scenario: Test unhandled thread meta data for plain Spring app - When I run plain Spring "UnhandledThreadMetaDataScenario" with the defaults +Scenario: Test unhandled thread metadata for plain Spring app + When I run plain Spring "UnhandledThreadMetadataScenario" with the defaults And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier And the error payload field "events" is an array with 1 elements @@ -121,8 +121,8 @@ Scenario: Test unhandled thread meta data for plain Spring app And the event "metaData.Custom.bar" equals "Thread value 2" And the event "metaData.Custom.something" is null -Scenario: Test logback appender with thread meta data - When I run "LogbackThreadMetaDataScenario" with logback config "basic_config.xml" +Scenario: Test logback appender with thread metadata + When I run "LogbackThreadMetadataScenario" with logback config "basic_config.xml" And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier And the error payload field "events" is an array with 1 elements @@ -137,14 +137,14 @@ Scenario: Test thread meta data in plain spring async method And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier And the event "metaData.thread.key1" is null - And the event "metaData.thread.key2" equals "should be included in meta data" + And the event "metaData.thread.key2" equals "should be included in metadata" Scenario: Test thread meta data in spring boot async method When I run spring boot "AsyncMethodScenario" with the defaults And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier And the event "metaData.thread.key1" is null - And the event "metaData.thread.key2" equals "should be included in meta data" + And the event "metaData.thread.key2" equals "should be included in metadata" Scenario: Test thread meta data in plain spring scheduled task Given I set environment variable "RUN_SCHEDULED_TASK" to "true" @@ -152,11 +152,11 @@ Scenario: Test thread meta data in plain spring scheduled task And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier And the event "metaData.thread.key1" is null - And the event "metaData.thread.key2" equals "should be included in meta data" + And the event "metaData.thread.key2" equals "should be included in metadata" Scenario: Test thread meta data in spring boot scheduled task When I run spring boot "ScheduledTaskScenario" with the defaults And I wait to receive an error And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier And the event "metaData.thread.key1" is null - And the event "metaData.thread.key2" equals "should be included in meta data" + And the event "metaData.thread.key2" equals "should be included in metadata" diff --git a/features/project_package.feature b/features/project_package.feature index e2dbc6c5..348f4858 100644 --- a/features/project_package.feature +++ b/features/project_package.feature @@ -13,7 +13,7 @@ Scenario: Test logback appender with no project packages And the event "exceptions.0.stacktrace.1.inProject" is false And the event "exceptions.0.stacktrace.2.method" equals "com.bugsnag.mazerunner.TestCaseRunner.run" And the event "exceptions.0.stacktrace.2.inProject" is false - And the event "exceptions.0.stacktrace.3.method" equals "org.springframework.boot.SpringApplication.callRunner" + And the event "exceptions.0.stacktrace.3.method" equals "org.springframework.boot.SpringApplication.lambda$callRunner$5" And the event "exceptions.0.stacktrace.3.inProject" is false Scenario: Test logback appender with a project package "com.bugsnag.mazerunner" defined @@ -29,7 +29,7 @@ Scenario: Test logback appender with a project package "com.bugsnag.mazerunner" And the event "exceptions.0.stacktrace.1.inProject" is true And the event "exceptions.0.stacktrace.2.method" equals "com.bugsnag.mazerunner.TestCaseRunner.run" And the event "exceptions.0.stacktrace.2.inProject" is true - And the event "exceptions.0.stacktrace.3.method" equals "org.springframework.boot.SpringApplication.callRunner" + And the event "exceptions.0.stacktrace.3.method" equals "org.springframework.boot.SpringApplication.lambda$callRunner$5" And the event "exceptions.0.stacktrace.3.inProject" is false Scenario: Test plain Java app with no project packages @@ -44,7 +44,7 @@ Scenario: Test plain Java app with no project packages And the event "exceptions.0.stacktrace.1.inProject" is false And the event "exceptions.0.stacktrace.2.method" equals "com.bugsnag.mazerunner.TestCaseRunner.run" And the event "exceptions.0.stacktrace.2.inProject" is false - And the event "exceptions.0.stacktrace.3.method" equals "org.springframework.boot.SpringApplication.callRunner" + And the event "exceptions.0.stacktrace.3.method" equals "org.springframework.boot.SpringApplication.lambda$callRunner$5" And the event "exceptions.0.stacktrace.3.inProject" is false Scenario: Test plain Java app with a project package "com.bugsnag.mazerunner" defined @@ -59,5 +59,5 @@ Scenario: Test plain Java app with a project package "com.bugsnag.mazerunner" de And the event "exceptions.0.stacktrace.1.inProject" is true And the event "exceptions.0.stacktrace.2.method" equals "com.bugsnag.mazerunner.TestCaseRunner.run" And the event "exceptions.0.stacktrace.2.inProject" is true - And the event "exceptions.0.stacktrace.3.method" equals "org.springframework.boot.SpringApplication.callRunner" + And the event "exceptions.0.stacktrace.3.method" equals "org.springframework.boot.SpringApplication.lambda$callRunner$5" And the event "exceptions.0.stacktrace.3.inProject" is false diff --git a/features/redacting_metadata.feature b/features/redacting_metadata.feature new file mode 100644 index 00000000..9585d111 --- /dev/null +++ b/features/redacting_metadata.feature @@ -0,0 +1,55 @@ +Feature: Metadata is redacted + +Scenario: Using the default metadata redaction + When I run "AutoRedactScenario" with the defaults + And I wait to receive an error + And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier + And the exception "message" equals "AutoRedactScenario" + And the event "metaData.custom.foo" equals "hunter2" + And the event "metaData.custom.password" equals "[REDACTED]" + And the event "metaData.user.password" equals "[REDACTED]" + +Scenario: Adding a custom metadata redaction + When I run "ManualRedactScenario" with the defaults + And I wait to receive an error + And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier + And the exception "message" equals "ManualRedactScenario" + And the event "metaData.custom.foo" equals "[REDACTED]" + And the event "metaData.user.foo" equals "[REDACTED]" + And the event "metaData.custom.bar" equals "hunter2" + +Scenario: Adding a thread metadata redaction using logback + When I run "LogbackThreadMetadataScenario" with logback config "meta_data_redact_config.xml" + And I wait to receive an error + And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier + And the exception "message" equals "LogbackThreadMetadataScenario" + And the event "metaData.thread.foo" equals "[REDACTED]" + And the event "metaData.thread.bar" equals "threadvalue2" + +Scenario: Adding a custom metadata redaction using logback + When I run "LogbackMetadataScenario" with logback config "meta_data_redact_config.xml" + And I wait to receive an error + And the error is valid for the error reporting API version "4" for the "Bugsnag Java" notifier + And the exception "message" equals "LogbackMetadataScenario" + And the event "metaData.custom.foo" equals "[REDACTED]" + And the event "metaData.user.foo" equals "[REDACTED]" + And the event "metaData.custom.bar" equals "hunter2" + +Scenario: Using the default metadata redaction in Spring Boot app + When I run spring boot "AutoRedactScenario" with the defaults + And I wait to receive an error + And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier + And the exception "message" equals "AutoRedactScenario" + And the event "metaData.custom.foo" equals "hunter2" + And the event "metaData.custom.password" equals "[REDACTED]" + And the event "metaData.user.password" equals "[REDACTED]" + +Scenario: Using the default metadata redaction in Spring app + When I run plain Spring "AutoRedactScenario" with the defaults + And I wait to receive an error + And the error is valid for the error reporting API version "4" for the "Bugsnag Spring" notifier + And the exception "message" equals "AutoRedactScenario" + And the event "metaData.custom.foo" equals "hunter2" + And the event "metaData.custom.password" equals "[REDACTED]" + And the event "metaData.user.password" equals "[REDACTED]" + diff --git a/features/scripts/assemble-fixtures.sh b/features/scripts/assemble-fixtures.sh index 1f53250c..27e63dc5 100755 --- a/features/scripts/assemble-fixtures.sh +++ b/features/scripts/assemble-fixtures.sh @@ -1,6 +1,12 @@ #!/usr/bin/env bash -if [ ! -d "features/fixtures/libs" ]; then - mkdir -p features/fixtures/libs - unzip maven-repository.zip -d features/fixtures/libs +# Remove existing directory if it exists +if [ -d "features/fixtures/libs" ]; then + rm -rf features/fixtures/libs fi + +# Recreate the directory +mkdir -p features/fixtures/libs + +# Unzip the contents into it +unzip maven-repository.zip -d features/fixtures/libs \ No newline at end of file diff --git a/features/scripts/build-plain-spring-app.sh b/features/scripts/build-plain-spring-app.sh index 12c65cd6..4a8f751d 100755 --- a/features/scripts/build-plain-spring-app.sh +++ b/features/scripts/build-plain-spring-app.sh @@ -2,10 +2,5 @@ # Start Tomcat then copy a WAR file across to serve it catalina.sh start -if [[ "${JAVA_VERSION}" == "8"* ]]; then - ./gradlew -p features/fixtures/mazerunnerplainspring war - cp features/fixtures/mazerunnerplainspring/build/libs/mazerunnerplainspring.war $CATALINA_HOME/webapps/ROOT.war -else - ./gradlew -p features/fixtures/mazerunnerplainspring6 war - cp features/fixtures/mazerunnerplainspring6/build/libs/mazerunnerplainspring.war $CATALINA_HOME/webapps/ROOT.war -fi \ No newline at end of file +./gradlew -p features/fixtures/mazerunnerplainspring6 war +cp features/fixtures/mazerunnerplainspring6/build/libs/mazerunnerplainspring.war $CATALINA_HOME/webapps/ROOT.war diff --git a/features/scripts/run-java-spring-boot-app.sh b/features/scripts/run-java-spring-boot-app.sh index 378dc467..239f1131 100755 --- a/features/scripts/run-java-spring-boot-app.sh +++ b/features/scripts/run-java-spring-boot-app.sh @@ -1,9 +1,4 @@ #!/usr/bin/env bash catalina.sh stop -if [[ "${JAVA_VERSION}" == "8"* ]]; then - cd features/fixtures/mazerunnerspringboot - ./gradlew bootRun -else - ./gradlew -p features/fixtures/mazerunnerspringboot3 bootRun -fi \ No newline at end of file +./gradlew -p features/fixtures/mazerunnerspringboot3 bootRun \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000..23a4ffe1 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,68 @@ +[versions] +# Build plugins +gradleLicense = "0.16.1" +checkstyle = "8.18" +gretty = "4.0.3" + +# Java/Kotlin toolchain +java = "17" + +# Main dependencies +jackson = "2.14.1" +slf4j = "1.7.25" +logback = "1.2.3" +jakartaServlet = "5.0.0" + +# Spring +spring = "6.0.0" +springBoot2 = "2.5.14" +springBoot3 = "3.0.0" + +# Testing +junit = "4.13.2" +junitJupiter = "5.8.2" +mockito = "5.0.0" +mockitoLegacy = "2.10.0" + +[libraries] +# Jackson +jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" } + +# SLF4J +slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } +slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" } +log4j-over-slf4j = { module = "org.slf4j:log4j-over-slf4j", version.ref = "slf4j" } + +# Logback +logback-core = { module = "ch.qos.logback:logback-core", version.ref = "logback" } +logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } + +# Jakarta +jakarta-servlet-api = { module = "jakarta.servlet:jakarta.servlet-api", version.ref = "jakartaServlet" } + +# Spring Framework +spring-webmvc = { module = "org.springframework:spring-webmvc", version.ref = "spring" } +spring-aop = { module = "org.springframework:spring-aop", version.ref = "spring" } + +# Spring Boot 2.x +springBoot2-gradle-plugin = { module = "org.springframework.boot:spring-boot-gradle-plugin", version.ref = "springBoot2" } +springBoot2-starter = { module = "org.springframework.boot:spring-boot-starter", version.ref = "springBoot2" } +springBoot2-starter-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "springBoot2" } + +# Spring Boot 3.x +springBoot3-boot = { module = "org.springframework.boot:spring-boot", version.ref = "springBoot3" } +springBoot3-starter-test = { module = "org.springframework.boot:spring-boot-starter-test", version.ref = "springBoot3" } +springBoot3-starter-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "springBoot3" } + +# Testing +junit = { module = "junit:junit", version.ref = "junit" } +junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junitJupiter" } +mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" } +mockito-core-legacy = { module = "org.mockito:mockito-core", version.ref = "mockitoLegacy" } + +# Build tools +gretty = { module = "org.gretty:gretty", version.ref = "gretty" } + +[plugins] +license = { id = "com.github.hierynomus.license", version.ref = "gradleLicense" } + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 05376a7d..4e3b050f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip diff --git a/release.gradle b/release.gradle deleted file mode 100644 index 4cb9e10d..00000000 --- a/release.gradle +++ /dev/null @@ -1,75 +0,0 @@ -apply plugin: 'maven-publish' -apply plugin: 'signing' - -archivesBaseName = project.findProperty('artifactId') - -tasks.maybeCreate('sourceJar', Jar).configure { - from java.sourceSets.main.allJava -} - -publishing { - - repositories { - maven { - name = 'ossrhStaging' - url = "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/" - credentials { - username = project.hasProperty("NEXUS_USERNAME") ? "$NEXUS_USERNAME" : System.getenv("NEXUS_USERNAME") - password = project.hasProperty("NEXUS_PASSWORD") ? "$NEXUS_PASSWORD" : System.getenv("NEXUS_PASSWORD") - } - } - - maven { - name 'test' - url rootProject.file('build/repository').toURI().toString() - } - } - - publications { - Publication(MavenPublication) { - from project(':' + project.name).components.java - groupId 'com.bugsnag' - artifactId project.findProperty('artifactId') - version rootProject.version - artifact sourceJar { - classifier "sources" - } - pom { - name = project.findProperty('projectName') - description = project.findProperty('projectDescription') - url = 'https://github.com/bugsnag/bugsnag-java' - - scm { - url = 'https://github.com/bugsnag/bugsnag-java' - connection = 'scm:git:git://github.com/bugsnag/bugsnag-java.git' - developerConnection = 'scm:git:ssh://git@github.com/bugsnag/bugsnag-java.git' - } - - licenses { - license { - name = 'MIT' - url = 'http://opensource.org/licenses/MIT' - distribution = 'repo' - } - } - - organization { - name = 'Bugsnag' - url = 'https://bugsnag.com' - } - - developers { - developer { - id = 'loopj' - name = 'James Smith' - email = 'james@bugsnag.com' - } - } - } - } - } - - signing { - sign publishing.publications - } -} diff --git a/release.gradle.kts b/release.gradle.kts new file mode 100644 index 00000000..bb62cb2b --- /dev/null +++ b/release.gradle.kts @@ -0,0 +1,125 @@ +// release.gradle.kts — script plugin (apply from: ...) + +apply(plugin = "java") +apply(plugin = "maven-publish") +apply(plugin = "signing") + +/** -------- Helpers -------- */ +fun projectProperty(k: String): String? = project.findProperty(k) as String? +fun projectBoolean(k: String): Boolean = projectProperty(k)?.toBoolean() ?: false + +val isRelease = projectBoolean("releasing") // set with -Preleasing=true on real deploys + +// Prefer Gradle properties (works on CI without env vars). +// Put these in ~/.gradle/gradle.properties or project gradle.properties on CI. +val ossrhUser = projectProperty("NEXUS_USERNAME") ?: projectProperty("ossrhUsername") +val ossrhPass = projectProperty("NEXUS_PASSWORD") ?: projectProperty("ossrhPassword") + +// Optional in-memory signing keys (recommended for CI) +// signingKey: ASCII-armored private key, signingPassword: key passphrase +val signingKey = projectProperty("signingKey") +val signingPassword = projectProperty("signingPassword") + +/** -------- Java / Artifacts -------- */ +configure { + archivesName.set(projectProperty("artifactId") ?: project.name) +} + +configure { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } + withSourcesJar() + withJavadocJar() +} + +/** -------- Publishing -------- */ +configure { + repositories { + // Always-available local test repo + maven { + name = "test" + url = uri(rootProject.file("build/repository")) + } + + // OSSRH only if credentials are available (no envs needed) + if (ossrhUser != null && ossrhPass != null) { + maven { + name = "ossrhStaging" + url = uri("https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/") + credentials { + username = ossrhUser + password = ossrhPass + } + } + } else { + logger.lifecycle("[publishing] OSSRH credentials not provided; skipping remote repository configuration.") + } + } + + publications { + create("mavenJava") { + from(components["java"]) + + groupId = "com.bugsnag" + artifactId = projectProperty("artifactId") ?: project.name + version = rootProject.version.toString() + + pom { + name.set(projectProperty("projectName") ?: artifactId) + description.set(projectProperty("projectDescription") ?: "Bugsnag Java Notifier") + url.set("https://github.com/bugsnag/bugsnag-java") + + scm { + url.set("https://github.com/bugsnag/bugsnag-java") + connection.set("scm:git:git://github.com/bugsnag/bugsnag-java.git") + developerConnection.set("scm:git:ssh://git@github.com/bugsnag/bugsnag-java.git") + } + + licenses { + license { + name.set("MIT") + url.set("http://opensource.org/licenses/MIT") + distribution.set("repo") + } + } + + organization { + name.set("Bugsnag") + url.set("https://bugsnag.com") + } + + developers { + developer { + id.set("loopj") + name.set("James Smith") + email.set("james@bugsnag.com") + } + } + } + } + } +} + +/** -------- Signing (no .asc on test publishes) -------- */ +configure { + // Only *require* signing for real releases + setRequired { isRelease } + + // Only attach signatures when we actually want to sign + if (isRelease) { + if (signingKey != null && signingPassword != null) { + useInMemoryPgpKeys(signingKey, signingPassword) + } + sign(the().publications["mavenJava"]) + } +} + +/** -------- Safety: never try publishing to OSSRH without creds -------- */ +tasks.withType().configureEach { + onlyIf { + // Allow all "test" publishes, and only allow OSSRH when creds exist + repository?.name != "ossrhStaging" || (ossrhUser != null && ossrhPass != null) + } +} + diff --git a/scripts/build-test-repository.sh b/scripts/build-test-repository.sh index 948547fe..1a01ed87 100755 --- a/scripts/build-test-repository.sh +++ b/scripts/build-test-repository.sh @@ -1,4 +1,11 @@ #!/usr/bin/env bash -./gradlew -xsignPublicationPublication -Preleasing=true -Pversion=9.9.9-test publishPublicationPublicationToTestRepository -cd build/repository/ || exit -zip -r ../../maven-repository.zip ./* +set -euo pipefail +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT_DIR" + +./gradlew -Pversion=9.9.9-test publishToTestRepoAll + +REPO_DIR="$ROOT_DIR/build/repository" +mkdir -p "$REPO_DIR" +cd "$REPO_DIR" +zip -r "$ROOT_DIR/maven-repository.zip" ./* \ No newline at end of file diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 596924ce..00000000 --- a/settings.gradle +++ /dev/null @@ -1,13 +0,0 @@ -include ':bugsnag', - ':bugsnag-spring' - -include ':examples:simple', - ':examples:servlet-javax', - ':examples:spring', - ':examples:spring-web', - ':examples:logback' - -// jakarta servlet example requires java 11 compatibility for gretty plugin -if (JavaVersion.current().isJava11Compatible()) { - include ':examples:servlet-jakarta' -} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..caa631b3 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,10 @@ + +include(":bugsnag") +include(":bugsnag-spring") + +include(":examples:simple") +include(":examples:spring") +include(":examples:spring-web") +include(":examples:logback") +include(":examples:servlet-jakarta") +