diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml new file mode 100644 index 00000000..e93b361d --- /dev/null +++ b/.github/workflows/build-publish.yml @@ -0,0 +1,40 @@ +name: Build and Publish + +# Thin caller around the shared reusable workflow in +# NrgXnat/xnat-ci-workflows. Plugin variant — no GHCR Docker image +# (plugins ship a jar to JFrog only). + +on: + push: + branches: + - main + - dev # container-service uses 'dev' instead of 'develop' + - 'releases/*' # RC / release branches, e.g. releases/1.6.0-rc + workflow_dispatch: + inputs: + publish_jfrog: + description: 'Publish jar to JFrog Artifactory (nrgxnat)' + type: boolean + default: false + +permissions: + contents: read + packages: write # required by reusable workflow's publish-ghcr job (gated by if: inputs.publish-ghcr but parsed at startup) + +jobs: + build-publish: + uses: NrgXnat/xnat-ci-workflows/.github/workflows/gradle-build-publish.yml@v1 + with: + # ──── Artifact ──── + artifact-glob: 'build/libs/*.jar' + artifact-name: 'container-service-jar' + + # ──── JFrog ──── + # On any push to a triggered branch: publish. On dispatch: only when publish_jfrog ticked. + publish-jfrog: ${{ github.event_name == 'push' || inputs.publish_jfrog }} + + # publish-ghcr deliberately omitted — defaults to false in the reusable workflow. + + # secrets: inherit passes XNAT_ARTIFACTORY_USER/TOKEN (org-level) and + # the auto-injected GITHUB_TOKEN through to the reusable workflow. + secrets: inherit diff --git a/.github/workflows/release-cut-rc.yml b/.github/workflows/release-cut-rc.yml new file mode 100644 index 00000000..17090344 --- /dev/null +++ b/.github/workflows/release-cut-rc.yml @@ -0,0 +1,37 @@ +name: Release - Cut RC Branch + +# Thin caller around the shared reusable workflow in NrgXnat/xnat-ci-workflows. +# Cuts a `releases/-rc` branch from source_branch and bumps +# source_branch to the next dev version. All release-cut logic lives in the +# reusable workflow; this file only defines our triggers + inputs. + +on: + workflow_dispatch: + inputs: + next_dev_version: + description: 'Next dev SNAPSHOT version (e.g. 1.7.0-SNAPSHOT)' + type: string + required: true + source_branch: + description: 'Branch to cut from (default: dev)' + type: string + required: false + default: dev + trigger_build: + description: 'After cut, dispatch build/publish on RC and source_branch' + type: boolean + required: false + default: true + +permissions: + contents: write + actions: write # dispatch build-publish workflow + +jobs: + cut-rc: + uses: NrgXnat/xnat-ci-workflows/.github/workflows/gradle-release-cut-rc.yml@v1 + with: + next_dev_version: ${{ inputs.next_dev_version }} + source_branch: ${{ inputs.source_branch }} + trigger_build: ${{ inputs.trigger_build }} + secrets: inherit diff --git a/.github/workflows/release-promote.yml b/.github/workflows/release-promote.yml new file mode 100644 index 00000000..09416fbd --- /dev/null +++ b/.github/workflows/release-promote.yml @@ -0,0 +1,37 @@ +name: Release - Promote RC to Main + +# Thin caller around the shared reusable workflow in NrgXnat/xnat-ci-workflows. +# Promotes a stabilized RC branch to a tagged release on target_main. All +# release-promote logic lives in the reusable workflow; this file only defines +# our triggers + inputs. + +on: + workflow_dispatch: + inputs: + rc_branch: + description: 'RC branch to promote (e.g. releases/1.6.0-rc)' + type: string + required: true + target_main: + description: 'Branch to merge into (default main)' + type: string + required: false + default: main + trigger_build: + description: 'After promote, dispatch build/publish on target_main' + type: boolean + required: false + default: true + +permissions: + contents: write # push RC/main + create tag + actions: write # dispatch build-publish workflow + +jobs: + promote: + uses: NrgXnat/xnat-ci-workflows/.github/workflows/gradle-release-promote.yml@v1 + with: + rc_branch: ${{ inputs.rc_branch }} + target_main: ${{ inputs.target_main }} + trigger_build: ${{ inputs.trigger_build }} + secrets: inherit diff --git a/build.gradle b/build.gradle index 592460c6..59d64084 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ buildscript { ext { - vXnat = "1.9.3" + vXnat = "1.10.1-SNAPSHOT" pluginAppName = "XNAT Container Service" } } @@ -12,18 +12,17 @@ plugins { id "com.palantir.git-version" version "3.3.0" id "io.spring.dependency-management" version "1.1.7" id "io.franzbecker.gradle-lombok" version "5.0.0" - id "net.linguica.maven-settings" version "0.5" } group "org.nrg.xnatx.plugins" version "3.9.0-SNAPSHOT" java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = 21 + targetCompatibility = 21 } -def vMockito = "1.10.19" +def vMockito = "5.7.0" def vJavassist = "3.21.0-GA" def vAwaitility = "2.0.0" @@ -38,7 +37,6 @@ dependencyManagement { imports { mavenBom("org.nrg:parent:${vXnat}") { bomProperties([ - "mockito.version": vMockito, "javassist.version": vJavassist ]) } @@ -46,24 +44,33 @@ dependencyManagement { } def vDockerJava = "3.4.0.1" -def vAutoValue = "1.3" +def vAutoValue = "1.5.4" def vKubernetesClient = "15.0.+" -def vPowerMock = "1.7.0" -def vGson = dependencyManagement.importedProperties["gson.version"] -def vJackson = dependencyManagement.importedProperties["jackson.version"] -def vSpringSecurity = dependencyManagement.importedProperties["spring-security.version"] -def vActiveMQ = dependencyManagement.importedProperties["activemq.version"] +def vPowerMock = "2.0.9" +// importedProperties not available from Gradle java-platform BOM — versions managed by BOM directly // Use this configuration to put dependencies into the fat jar configurations { implementation.extendsFrom(implementAndInclude) all { resolutionStrategy.force "org.mockito:mockito-core:${vMockito}" + resolutionStrategy.force "com.github.docker-java:docker-java-api:${vDockerJava}" exclude group: "org.bouncycastle" } } +tasks.withType(Test).configureEach { +// jvmArgs("--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED") + jvmArgs("--add-opens", "java.xml/jdk.xml.internal=ALL-UNNAMED") + jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED") + } + +lombok { + version = "1.18.34" + sha256 = "1ea5ad6c6afcff902d75072b2aaa6695585aebee9f12127e15c0036ba95d2918" +} + dependencies { annotationProcessor "org.nrg:framework" annotationProcessor "com.google.auto.value:auto-value:${vAutoValue}" @@ -105,9 +112,7 @@ dependencies { implementation ("org.nrg.xdat:core") { transitive = false } - implementation ("org.nrg.xnat:xnat-data-models") { - transitive = false - } + // xnat-data-models merged into org.nrg.xnat:web in monorepo — no longer a separate artifact implementation "org.nrg:prefs" implementation ("org.nrg:notify") { exclude group: "cglib" @@ -131,8 +136,8 @@ dependencies { implementation "org.springframework:spring-webmvc" implementation "org.springframework:spring-jms" implementation "org.springframework:spring-messaging" - implementation "javax.jms:javax.jms-api:2.0.1" - implementation "org.apache.activemq:activemq-all:${vActiveMQ}" + implementation "javax.jms:javax.jms-api" + implementation "org.apache.activemq:activemq-all" implementation "org.aspectj:aspectjweaver" implementation "io.springfox:springfox-swagger2" @@ -144,8 +149,8 @@ dependencies { implementation "com.fasterxml.jackson.core:jackson-annotations" implementation "com.fasterxml.jackson.core:jackson-core" implementation "com.fasterxml.jackson.core:jackson-databind" - implementation "com.fasterxml.jackson.module:jackson-module-jaxb-annotations:${vJackson}" - implementation "com.fasterxml.jackson.datatype:jackson-datatype-guava:${vJackson}" + implementation "com.fasterxml.jackson.module:jackson-module-jaxb-annotations" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-guava" implementation "com.jayway.jsonpath:json-path" @@ -163,7 +168,7 @@ dependencies { implementation ("org.apache.velocity:velocity") { transitive = false } - implementation ("xalan:xalan") { + implementation ("xalan:xalan:2.7.2") { transitive = false } @@ -174,39 +179,47 @@ dependencies { runtimeOnly "org.apache.commons:commons-compress" runtimeOnly "org.apache.commons:commons-lang3" runtimeOnly "org.apache.httpcomponents:httpclient" - runtimeOnly "com.google.code.gson:gson:${vGson}" + runtimeOnly "com.google.code.gson:gson" runtimeOnly "com.google.code.findbugs:jsr305" runtimeOnly "org.yaml:snakeyaml:1.15+" - testImplementation "junit:junit" + testImplementation "junit:junit:4.13.2" + testImplementation(platform('org.junit:junit-bom:5.10.2')) + testImplementation 'org.junit.jupiter:junit-jupiter' + testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testImplementation "org.hamcrest:hamcrest-library" testImplementation "org.springframework:spring-test" - testImplementation "org.springframework.security:spring-security-test:${vSpringSecurity}" + testImplementation "org.springframework.security:spring-security-test" testImplementation "org.springframework.security:spring-security-config" - testImplementation "org.mockito:mockito-core" + testImplementation "org.mockito:mockito-core:${vMockito}" + testImplementation 'org.mockito:mockito-junit-jupiter:5.0.0' // JUnit 5 integration for Mockito + testImplementation "javax.servlet:javax.servlet-api" testImplementation "com.h2database:h2" testImplementation "org.springframework:spring-jdbc" testImplementation "org.springframework:spring-orm" testImplementation "org.apache.commons:commons-dbcp2" testImplementation "commons-net:commons-net" - testImplementation "org.powermock:powermock-module-junit4:${vPowerMock}" - testImplementation "org.powermock:powermock-api-mockito:${vPowerMock}" testImplementation "org.awaitility:awaitility:${vAwaitility}" testImplementation "org.testcontainers:junit-jupiter:1.19.0" testImplementation "org.testcontainers:postgresql:1.19.0" } test { + useJUnitPlatform() systemProperty "integration", System.getProperty('integration') == "true" } tasks.register ( 'unitTest', Test ) { + useJUnitPlatform() + systemProperties['integration'] = "false" test } tasks.register ( 'integrationTest', Test ) { + useJUnitPlatform() systemProperties['integration'] = "true" test } @@ -236,23 +249,23 @@ try { isCleanTag = false } -ext.gitManifest = manifest { - attributes "Application-Name": pluginAppName, - "Build-Date": buildDate, - "Build-Number": buildNumber, - "Implementation-Version": project.version, - "Implementation-Sha": gitHash, - "Implementation-Sha-Full": gitHashFull, - "Implementation-Commit": commitDistance, - "Implementation-LastTag": lastTag, - "Implementation-Branch": branchName, - "Implementation-CleanTag": isCleanTag, - "Implementation-Dirty": isDirty -} +ext.gitManifestAttrs = [ + "Application-Name" : pluginAppName, + "Build-Date" : buildDate, + "Build-Number" : buildNumber, + "Implementation-Version" : project.version, + "Implementation-Sha" : gitHash, + "Implementation-Sha-Full" : gitHashFull, + "Implementation-Commit" : commitDistance, + "Implementation-LastTag" : lastTag, + "Implementation-Branch" : branchName, + "Implementation-CleanTag" : isCleanTag, + "Implementation-Dirty" : isDirty +] task fatJar(type: Jar) { zip64 true - classifier = "fat" + archiveClassifier.set("fat") from { configurations.implementAndInclude.collect { it.isDirectory() ? it : zipTree(it) } } { @@ -262,7 +275,7 @@ task fatJar(type: Jar) { } duplicatesStrategy "exclude" manifest { - from gitManifest + attributes gitManifestAttrs } with jar } @@ -274,7 +287,7 @@ sourceSets.main.java { jar{ manifest { - from gitManifest + attributes gitManifestAttrs } doLast { if (!gradle.taskGraph.hasTask(":fatJar")) { @@ -284,17 +297,17 @@ jar{ } task sourceJar(type: Jar, dependsOn: classes) { - classifier = "sources" + archiveClassifier.set("sources") manifest { - from gitManifest + attributes gitManifestAttrs } from sourceSets.main.allSource } task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = "javadoc" + archiveClassifier.set("javadoc") manifest { - from gitManifest + attributes gitManifestAttrs } from javadoc.destinationDir } @@ -345,13 +358,17 @@ publishing { } repositories { maven { - if (project.version.endsWith("-SNAPSHOT")) { - url "https://nrgxnat.jfrog.io/nrgxnat/libs-snapshot-local" - } else { - url "https://nrgxnat.jfrog.io/nrgxnat/libs-release-local" - } - // The value for name must match in ~/.m2/settings.xml name = "XNAT_Artifactory" + url = project.version.toString().endsWith("-SNAPSHOT") + ? "https://nrgxnat.jfrog.io/nrgxnat/libs-snapshot-local" + : "https://nrgxnat.jfrog.io/nrgxnat/libs-release-local" + // CI injects ORG_GRADLE_PROJECT_artifactoryUser/Token env vars (Gradle maps + // these to project properties). Local devs can set artifactoryUser/Token in + // ~/.gradle/gradle.properties. Mirrors monorepo's buildSrc convention. + credentials { + username = (project.findProperty("artifactoryUser") ?: System.getenv("ARTIFACTORY_USER")) ?: "" + password = (project.findProperty("artifactoryToken") ?: System.getenv("ARTIFACTORY_TOKEN")) ?: "" + } } } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a..249e5832 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae04661e..221c4f98 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c7873..a69d9cb6 100755 --- a/gradlew +++ b/gradlew @@ -205,6 +205,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index ac1b06f9..53a6b238 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 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 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/src/main/java/org/nrg/containers/utils/KubernetesConfiguration.java b/src/main/java/org/nrg/containers/utils/KubernetesConfiguration.java index e8a6bede..35312cd8 100644 --- a/src/main/java/org/nrg/containers/utils/KubernetesConfiguration.java +++ b/src/main/java/org/nrg/containers/utils/KubernetesConfiguration.java @@ -136,7 +136,7 @@ public static Path find() { * * If a file cannot be found in those locations, returns null. * - * @return A KubeConfig if it can be found, or null + * @return A KubeConfig if it can be found, or null * @throws IOException if the configuration file or a file specified in a configuration file * cannot be read. */ diff --git a/src/test/java/org/nrg/containers/CommandLaunchIntegrationTest.java b/src/test/java/org/nrg/containers/CommandLaunchIntegrationTest.java index 543d6eda..5de542e2 100644 --- a/src/test/java/org/nrg/containers/CommandLaunchIntegrationTest.java +++ b/src/test/java/org/nrg/containers/CommandLaunchIntegrationTest.java @@ -12,11 +12,9 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.SystemUtils; import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; +import org.junit.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.rules.TemporaryFolder; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; @@ -24,6 +22,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.mockito.ArgumentMatcher; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.nrg.containers.api.DockerControlApi; import org.nrg.containers.api.KubernetesClient; @@ -36,12 +35,7 @@ import org.nrg.containers.model.container.auto.Container.ContainerMount; import org.nrg.containers.model.server.docker.Backend; import org.nrg.containers.model.server.docker.DockerServerBase.DockerServer; -import org.nrg.containers.model.xnat.FakeWorkflow; -import org.nrg.containers.model.xnat.Project; -import org.nrg.containers.model.xnat.Resource; -import org.nrg.containers.model.xnat.Scan; -import org.nrg.containers.model.xnat.Session; -import org.nrg.containers.model.xnat.XnatModelObject; +import org.nrg.containers.model.xnat.*; import org.nrg.containers.services.CommandService; import org.nrg.containers.services.ContainerService; import org.nrg.containers.services.DockerServerService; @@ -62,7 +56,6 @@ import org.nrg.xft.ItemI; import org.nrg.xft.XFTItem; import org.nrg.xft.event.EventDetails; -import org.nrg.xft.event.EventMetaI; import org.nrg.xft.event.persist.PersistentWorkflowI; import org.nrg.xft.event.persist.PersistentWorkflowUtils; import org.nrg.xft.schema.XFTManager; @@ -76,11 +69,6 @@ import org.nrg.xnat.services.archive.CatalogService; import org.nrg.xnat.turbine.utils.ArchivableItem; import org.nrg.xnat.utils.WorkflowUtils; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.modules.junit4.PowerMockRunnerDelegate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; @@ -91,66 +79,46 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.EnumSet; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.stream.Collectors; import static org.awaitility.Awaitility.await; -import static org.hamcrest.Matchers.arrayContainingInAnyOrder; -import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.Matchers.hasItemInArray; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.isEmptyOrNullString; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.startsWith; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.junit.Assume.assumeThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.argThat; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.nrg.containers.services.ContainerService.XNAT_EVENT_ID; -import static org.nrg.containers.services.ContainerService.XNAT_HOST; -import static org.nrg.containers.services.ContainerService.XNAT_PASS; -import static org.nrg.containers.services.ContainerService.XNAT_USER; -import static org.nrg.containers.services.ContainerService.XNAT_WORKFLOW_ID; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; +import static org.nrg.containers.services.ContainerService.*; import static org.nrg.containers.utils.TestingUtils.BUSYBOX; -import static org.powermock.api.mockito.PowerMockito.doNothing; -import static org.powermock.api.mockito.PowerMockito.doReturn; -import static org.powermock.api.mockito.PowerMockito.mockStatic; @Slf4j -@RunWith(PowerMockRunner.class) -@PowerMockRunnerDelegate(Parameterized.class) -@PrepareForTest({UriParserUtils.class, XFTManager.class, Users.class, WorkflowUtils.class, - PersistentWorkflowUtils.class, XDATServlet.class, Session.class, ContainerServicePermissionUtils.class, - org.nrg.xnat.utils.FileUtils.class}) -@PowerMockIgnore({"org.apache.*", "java.*", "javax.*", "org.w3c.*", "com.sun.*"}) +@RunWith(Parameterized.class) @ContextConfiguration(classes = EventPullingIntegrationTestConfig.class) @Parameterized.UseParametersRunnerFactory(SpringJUnit4ClassRunnerFactory.class) @Transactional public class CommandLaunchIntegrationTest { + private MockedStatic mockedContainerServicePermissionUtils; + + private MockedStatic mockedSession; + + private MockedStatic mockedXDATServlet; + + private MockedStatic mockedWorkflowUtils; + + private MockedStatic mockedUsers; + + private MockedStatic mockedXFTManager; + + private MockedStatic mockedUriParserUtils; + @Parameterized.Parameters(name = "backend={0}") public static Collection backend() { return EnumSet.allOf(Backend.class); @@ -218,18 +186,12 @@ public void setup() throws Exception { // Mock the user management service when(mockUserManagementServiceI.getUser(FAKE_USER)).thenReturn(mockUser); - // Mock UriParserUtils using PowerMock. This allows us to mock out - // the responses to its static method parseURI(). - mockStatic(UriParserUtils.class); - // Mock the aliasTokenService final AliasToken mockAliasToken = new AliasToken(); mockAliasToken.setAlias(FAKE_ALIAS); mockAliasToken.setSecret(FAKE_SECRET); when(mockAliasTokenService.issueTokenForUser(mockUser)).thenReturn(mockAliasToken); - - mockStatic(Users.class); - when(Users.getUser(FAKE_USER)).thenReturn(mockUser); + mockedUsers.when(() -> Users.getUser(FAKE_USER)).thenReturn(mockUser); // Mock the site config preferences final String buildDir = folder.newFolder().getAbsolutePath(); @@ -238,35 +200,22 @@ public void setup() throws Exception { when(mockSiteConfigPreferences.getBuildPath()).thenReturn(buildDir); // transporter makes a directory under build when(mockSiteConfigPreferences.getArchivePath()).thenReturn(archiveDir); // container logs get stored under archive when(mockSiteConfigPreferences.getProperty("processingUrl", FAKE_HOST)).thenReturn(FAKE_HOST); - - // Use powermock to mock out the static method XFTManager.isInitialized() and XDATServlet.isDatabasePopulateOrUpdateCompleted() - mockStatic(XFTManager.class); - when(XFTManager.isInitialized()).thenReturn(true); - mockStatic(XDATServlet.class); - when(XDATServlet.isDatabasePopulateOrUpdateCompleted()).thenReturn(true); + mockedXFTManager.when(XFTManager::isInitialized).thenReturn(true); + mockedXDATServlet.when(XDATServlet::isDatabasePopulateOrUpdateCompleted).thenReturn(true); // Also mock out workflow operations to return our fake workflow object fakeWorkflow = new FakeWorkflow(); - mockStatic(WorkflowUtils.class); - when(WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) + mockedWorkflowUtils.when(() -> WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) .thenReturn(fakeWorkflow); - doNothing().when(WorkflowUtils.class, "save", any(PersistentWorkflowI.class), isNull(EventMetaI.class)); - PowerMockito.spy(PersistentWorkflowUtils.class); - doReturn(fakeWorkflow).when(PersistentWorkflowUtils.class, "getOrCreateWorkflowData", eq(FakeWorkflow.defaultEventId), - eq(mockUser), any(XFTItem.class), any(EventDetails.class)); + doNothing().when(WorkflowUtils.class); + Mockito.spy(PersistentWorkflowUtils.class); + doReturn(fakeWorkflow).when(PersistentWorkflowUtils.class); // mock external FS check when(mockCatalogService.hasRemoteFiles(eq(mockUser), any(String.class))).thenReturn(false); - - // We can't load the XFT item in the session, so don't try - // This is only used to check the permissions, and we mock that response anyway, so we don't need a real value - mockStatic(Session.class); - when(Session.loadXnatImageSessionData(any(String.class), eq(mockUser))) + mockedSession.when(() -> Session.loadXnatImageSessionData(any(String.class), eq(mockUser))) .thenReturn(null); - - // Permissions checks - mockStatic(ContainerServicePermissionUtils.class); - when(ContainerServicePermissionUtils.canCreateOutputObject( + mockedContainerServicePermissionUtils.when(() -> ContainerServicePermissionUtils.canCreateOutputObject( eq(mockUser), any(String.class), any(XnatModelObject.class), any(Command.CommandWrapperOutput.class) )).thenReturn(true); @@ -315,6 +264,28 @@ public void cleanup() throws Exception { executorService.shutdown(); } + @BeforeEach + void setUpStaticMocks() { + mockedContainerServicePermissionUtils = mockStatic(ContainerServicePermissionUtils.class); + mockedSession = mockStatic(Session.class); + mockedXDATServlet = mockStatic(XDATServlet.class); + mockedWorkflowUtils = mockStatic(WorkflowUtils.class); + mockedUsers = mockStatic(Users.class); + mockedXFTManager = mockStatic(XFTManager.class); + mockedUriParserUtils = mockStatic(UriParserUtils.class); + } + + @AfterEach + void tearDownStaticMocks() { + mockedUriParserUtils.closeOnDemand(); + mockedXFTManager.closeOnDemand(); + mockedUsers.closeOnDemand(); + mockedWorkflowUtils.closeOnDemand(); + mockedXDATServlet.closeOnDemand(); + mockedSession.closeOnDemand(); + mockedContainerServicePermissionUtils.closeOnDemand(); + } + @Test @DirtiesContext public void testFakeReconAll() throws Exception { @@ -345,7 +316,7 @@ public void testFakeReconAll() throws Exception { final String sessionJson = mapper.writeValueAsString(session); final ArchivableItem mockSesItem = mock(ArchivableItem.class); final ExptURI mockUriObject = mock(ExptURI.class); - when(UriParserUtils.parseURI("/archive" + session.getUri())).thenReturn(mockUriObject); + mockedUriParserUtils.when(() -> UriParserUtils.parseURI("/archive" + session.getUri())).thenReturn(mockUriObject); when(mockUriObject.getSecurityItem()).thenReturn(mockSesItem); final String t1Scantype = "T1_TEST_SCANTYPE"; @@ -467,11 +438,8 @@ public void testProjectMount() throws Exception { // Create the mock objects we will need in order to verify permissions final ArchivableItem mockProjectItem = mock(ArchivableItem.class); final ExptURI mockUriObject = mock(ExptURI.class); - when(UriParserUtils.parseURI("/archive" + project.getUri())).thenReturn(mockUriObject); + mockedUriParserUtils.when(() -> UriParserUtils.parseURI("/archive" + project.getUri())).thenReturn(mockUriObject); when(mockUriObject.getSecurityItem()).thenReturn(mockProjectItem); - - // Mock util method for shared file paths - PowerMockito.mockStatic(org.nrg.xnat.utils.FileUtils.class); when(org.nrg.xnat.utils.FileUtils.getAllSharedPaths(project.getId(), mockUser, false, false, true, false)) .thenReturn(Collections.emptyMap()); @@ -624,7 +592,7 @@ public void testLaunchCommandWithSetupCommand() throws Exception { final ArchivableItem mockItem = mock(ArchivableItem.class); final ResourcesExptURI mockUriObject = mock(ResourcesExptURI.class); String uri = "/archive" + resourceInput.getUri(); - when(UriParserUtils.parseURI(uri)).thenReturn(mockUriObject); + mockedUriParserUtils.when(() -> UriParserUtils.parseURI(uri)).thenReturn(mockUriObject); when(mockUriObject.getSecurityItem()).thenReturn(mockItem); fakeWorkflow.setId(uri); ResourceData mockRD = mock(ResourceData.class); @@ -642,12 +610,12 @@ public void testLaunchCommandWithSetupCommand() throws Exception { FakeWorkflow setupWrapupWorkflow = new FakeWorkflow(); setupWrapupWorkflow.setWfid(111); setupWrapupWorkflow.setEventId(2); - doReturn(setupWrapupWorkflow).when(PersistentWorkflowUtils.class, "getOrCreateWorkflowData", eq(2), - eq(mockUser), any(XFTItem.class), any(EventDetails.class)); - when(WorkflowUtils.buildOpenWorkflow(eq(mockUser), eq(xsiType), eq(id), eq(project), any(EventDetails.class))) + doReturn(setupWrapupWorkflow).when(PersistentWorkflowUtils.class + ); + mockedWorkflowUtils.when(() -> WorkflowUtils.buildOpenWorkflow(eq(mockUser), eq(xsiType), eq(id), eq(project), any(EventDetails.class))) .thenReturn(setupWrapupWorkflow); - when(WorkflowUtils.getUniqueWorkflow(mockUser, setupWrapupWorkflow.getWorkflowId().toString())) + mockedWorkflowUtils.when(() -> WorkflowUtils.getUniqueWorkflow(mockUser, setupWrapupWorkflow.getWorkflowId().toString())) .thenReturn(setupWrapupWorkflow); // Time to launch this thing @@ -767,7 +735,7 @@ public void testLaunchCommandWithWrapupCommand() throws Exception { final ArchivableItem mockSessionItem = mock(ArchivableItem.class); final ExptURI mockUriObject = mock(ExptURI.class); String uri = "/archive" + sessionInput.getUri(); - when(UriParserUtils.parseURI(uri)).thenReturn(mockUriObject); + mockedUriParserUtils.when(() -> UriParserUtils.parseURI(uri)).thenReturn(mockUriObject); when(mockUriObject.getSecurityItem()).thenReturn(mockSessionItem); String id = "id"; String xsiType = "type"; @@ -783,12 +751,12 @@ public void testLaunchCommandWithWrapupCommand() throws Exception { FakeWorkflow setupWrapupWorkflow = new FakeWorkflow(); setupWrapupWorkflow.setWfid(111); setupWrapupWorkflow.setEventId(2); - doReturn(setupWrapupWorkflow).when(PersistentWorkflowUtils.class, "getOrCreateWorkflowData", eq(2), - eq(mockUser), any(XFTItem.class), any(EventDetails.class)); - when(WorkflowUtils.buildOpenWorkflow(eq(mockUser), eq(xsiType), eq(id), eq(project), any(EventDetails.class))) + doReturn(setupWrapupWorkflow).when(PersistentWorkflowUtils.class + ); + mockedWorkflowUtils.when(() -> WorkflowUtils.buildOpenWorkflow(eq(mockUser), eq(xsiType), eq(id), eq(project), any(EventDetails.class))) .thenReturn(setupWrapupWorkflow); - when(WorkflowUtils.getUniqueWorkflow(mockUser, setupWrapupWorkflow.getWorkflowId().toString())) + mockedWorkflowUtils.when(() -> WorkflowUtils.getUniqueWorkflow(mockUser, setupWrapupWorkflow.getWorkflowId().toString())) .thenReturn(setupWrapupWorkflow); // Time to launch this thing @@ -1104,15 +1072,15 @@ public void testScanUpload() throws Exception { final ExptURI mockSesUri = mock(ExptURI.class); final ExptScanURI mockScanUri = mock(ExptScanURI.class); final String uri = "/archive" + session.getUri() + "/scans/scanNew"; - when(UriParserUtils.getArchiveUri(mockScanItem)).thenReturn(uri); - when(UriParserUtils.parseURI(uri)).thenReturn(mockScanUri); - when(UriParserUtils.parseURI("/archive" + session.getUri())).thenReturn(mockSesUri); + mockedUriParserUtils.when(() -> UriParserUtils.getArchiveUri(mockScanItem)).thenReturn(uri); + mockedUriParserUtils.when(() -> UriParserUtils.parseURI(uri)).thenReturn(mockScanUri); + mockedUriParserUtils.when(() -> UriParserUtils.parseURI("/archive" + session.getUri())).thenReturn(mockSesUri); when(mockScanUri.getSecurityItem()).thenReturn(mockSessionItem); when(mockSesUri.getSecurityItem()).thenReturn(mockSessionItem); ArgumentMatcher matchesXml = new ArgumentMatcher() { @Override - public boolean matches(Object arg) { + public boolean matches(File arg) { if (!(arg instanceof File)) { return false; } @@ -1126,7 +1094,7 @@ public boolean matches(Object arg) { }; ArgumentMatcher> matchesFileList = new ArgumentMatcher>() { @Override - public boolean matches(Object arg) { + public boolean matches(List arg) { if (!(arg instanceof List)) { return false; } @@ -1228,15 +1196,15 @@ public void testAssessorUpload() throws Exception { final ExptURI mockSesUri = mock(ExptURI.class); final ExptAssessorURI mockAssessorUri = mock(ExptAssessorURI.class); final String uri = "/archive" + session.getUri() + "/assessors/assessorNew"; - when(UriParserUtils.getArchiveUri(mockAssessorItem)).thenReturn(uri); - when(UriParserUtils.parseURI(uri)).thenReturn(mockAssessorUri); - when(UriParserUtils.parseURI("/archive" + session.getUri())).thenReturn(mockSesUri); + mockedUriParserUtils.when(() -> UriParserUtils.getArchiveUri(mockAssessorItem)).thenReturn(uri); + mockedUriParserUtils.when(() -> UriParserUtils.parseURI(uri)).thenReturn(mockAssessorUri); + mockedUriParserUtils.when(() -> UriParserUtils.parseURI("/archive" + session.getUri())).thenReturn(mockSesUri); when(mockAssessorUri.getSecurityItem()).thenReturn(mockSessionItem); when(mockSesUri.getSecurityItem()).thenReturn(mockSessionItem); ArgumentMatcher matchesXml = new ArgumentMatcher() { @Override - public boolean matches(Object arg) { + public boolean matches(File arg) { if (!(arg instanceof File)) { return false; } @@ -1250,7 +1218,7 @@ public boolean matches(Object arg) { }; ArgumentMatcher> matchesFileList = new ArgumentMatcher>() { @Override - public boolean matches(Object arg) { + public boolean matches(List arg) { if (!(arg instanceof List)) { return false; } @@ -1345,7 +1313,7 @@ public void testCommandWithGenericResourcesGpu() throws Exception { // Create the mock objects we will need in order to verify permissions final ArchivableItem mockProjectItem = mock(ArchivableItem.class); final ExptURI mockUriObject = mock(ExptURI.class); - when(UriParserUtils.parseURI("/archive" + project.getUri())).thenReturn(mockUriObject); + mockedUriParserUtils.when(() -> UriParserUtils.parseURI("/archive" + project.getUri())).thenReturn(mockUriObject); when(mockUriObject.getSecurityItem()).thenReturn(mockProjectItem); final Map runtimeValues = Collections.singletonMap("project", projectJson); diff --git a/src/test/java/org/nrg/containers/CommandResolutionTest.java b/src/test/java/org/nrg/containers/CommandResolutionTest.java index ac93126e..a4142e3c 100644 --- a/src/test/java/org/nrg/containers/CommandResolutionTest.java +++ b/src/test/java/org/nrg/containers/CommandResolutionTest.java @@ -7,6 +7,7 @@ import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.tuple.Pair; import org.hamcrest.Matchers; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -15,8 +16,7 @@ import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; -import org.junit.runner.RunWith; -import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.nrg.containers.config.ObjectMapperConfig; import org.nrg.containers.exceptions.CommandResolutionException; @@ -53,9 +53,6 @@ import org.nrg.xdat.services.cache.UserDataCache; import org.nrg.xft.security.UserI; import org.nrg.xnat.services.archive.CatalogService; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; import java.io.File; import java.nio.file.Path; @@ -80,15 +77,14 @@ import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; @Slf4j -@RunWith(PowerMockRunner.class) -@PrepareForTest(Users.class) public class CommandResolutionTest { + private MockedStatic mockedUsers; public static final String HELLO_1 = "hello1.txt"; public static final String HELLO_2 = "hello2.txt"; public static final String SUBDIR = "subdir"; @@ -108,13 +104,13 @@ public class CommandResolutionTest { private CommandResolutionService commandResolutionService; - @Mock private SiteConfigPreferences siteConfigPreferences; - @Mock private DockerService dockerService; - @Mock private DockerServerService dockerServerService; - @Mock private CatalogService catalogService; - @Mock private UserDataCache userDataCache; - @Mock private CommandService commandService; - @Mock private SystemPropertySecretSource.ValueObtainer systemPropertyObtainer; + private DockerService dockerService = Mockito.mock(DockerService.class); + private SiteConfigPreferences siteConfigPreferences = Mockito.mock(SiteConfigPreferences.class); + private DockerServerService dockerServerService = Mockito.mock(DockerServerService.class); + private CatalogService catalogService = Mockito.mock(CatalogService.class); + private UserDataCache userDataCache = Mockito.mock(UserDataCache.class); + private CommandService commandService = Mockito.mock(CommandService.class); + private SystemPropertySecretSource.ValueObtainer systemPropertyObtainer = Mockito.mock(SystemPropertySecretSource.ValueObtainer.class); private ObjectMapper mapper; @@ -136,14 +132,13 @@ protected void finished(Description description) { @Before public void setup() throws Exception { - + mockedUsers = Mockito.mockStatic(Users.class); mapper = (new ObjectMapperConfig()).objectMapper(); // Mock out a user for tests. Will return this as "admin" user. userI = Mockito.mock(UserI.class); when(userI.getLogin()).thenReturn("mockUser"); - PowerMockito.mockStatic(Users.class); - PowerMockito.when(Users.getAdminUser()).thenReturn(userI); + mockedUsers.when(Users::getAdminUser).thenReturn(userI); // Read test data files for command + wrappers resourceDir = Paths.get(ClassLoader.getSystemResource("commandResolutionTest").toURI()).toString().replace("%20", " "); @@ -197,6 +192,11 @@ private CommandWrapper wrapperByName(final Command command, final String wrapper return wrapper; } + @After + public void tearDownStaticMocks() { + mockedUsers.closeOnDemand(); + } + @Test public void testSessionScanResource() throws Exception { final String commandWrapperName = "session-scan-resource"; @@ -703,8 +703,8 @@ public void testRemoteFilesMount() throws Exception { // Just copy the archive dir over for now (tests for pullResourceCatalogsToDestination in xnat-web and filesystems_plugin) doAnswer(inv -> { - String src = inv.getArgumentAt(2, String.class); - String dest = inv.getArgumentAt(3, String.class); + String src = inv.getArgument(2, String.class); + String dest = inv.getArgument(3, String.class); FileUtils.copyDirectory(new File(src), new File(dest)); return null; }).when(catalogService).pullResourceCatalogsToDestination(eq(userI), diff --git a/src/test/java/org/nrg/containers/ContainerCleanupIntegrationTest.java b/src/test/java/org/nrg/containers/ContainerCleanupIntegrationTest.java index 9ebd4553..062ab328 100644 --- a/src/test/java/org/nrg/containers/ContainerCleanupIntegrationTest.java +++ b/src/test/java/org/nrg/containers/ContainerCleanupIntegrationTest.java @@ -6,11 +6,7 @@ import io.kubernetes.client.openapi.apis.BatchV1Api; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.SystemUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; +import org.junit.*; import org.junit.rules.TemporaryFolder; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; @@ -57,27 +53,15 @@ import org.nrg.xnat.helpers.uri.UriParserUtils; import org.nrg.xnat.services.archive.CatalogService; import org.nrg.xnat.utils.WorkflowUtils; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.modules.junit4.PowerMockRunnerDelegate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Nullable; import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadLocalRandom; @@ -85,28 +69,24 @@ import java.util.function.Consumer; import static org.awaitility.Awaitility.await; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.startsWith; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.junit.Assume.assumeThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isNull; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; import static org.nrg.containers.utils.TestingUtils.BUSYBOX; -import static org.powermock.api.mockito.PowerMockito.doNothing; -import static org.powermock.api.mockito.PowerMockito.doReturn; -import static org.powermock.api.mockito.PowerMockito.mockStatic; +//import static org.powermock.api.mockito.PowerMockito.*; @Slf4j -@RunWith(PowerMockRunner.class) -@PowerMockRunnerDelegate(Parameterized.class) -@PrepareForTest({UriParserUtils.class, XFTManager.class, Users.class, WorkflowUtils.class, - PersistentWorkflowUtils.class, XDATServlet.class, Session.class, ContainerServicePermissionUtils.class}) -@PowerMockIgnore({"org.apache.*", "java.*", "javax.*", "org.w3c.*", "com.sun.*"}) +@RunWith(Parameterized.class) +//@PowerMockRunnerDelegate(Parameterized.class) +//@PrepareForTest({UriParserUtils.class, XFTManager.class, Users.class, WorkflowUtils.class, +// PersistentWorkflowUtils.class, XDATServlet.class, Session.class, ContainerServicePermissionUtils.class}) +//@PowerMockIgnore({"org.apache.*", "java.*", "javax.*", "org.w3c.*", "com.sun.*"}) @ContextConfiguration(classes = EventPullingIntegrationTestConfig.class) @Parameterized.UseParametersRunnerFactory(SpringJUnit4ClassRunnerFactory.class) @Transactional @@ -215,10 +195,10 @@ public void setup() throws Exception { mockStatic(WorkflowUtils.class); when(WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) .thenReturn(fakeWorkflow); - doNothing().when(WorkflowUtils.class, "save", any(PersistentWorkflowI.class), isNull(EventMetaI.class)); - PowerMockito.spy(PersistentWorkflowUtils.class); - doReturn(fakeWorkflow).when(PersistentWorkflowUtils.class, "getOrCreateWorkflowData", eq(FakeWorkflow.defaultEventId), - eq(mockUser), any(XFTItem.class), any(EventDetails.class)); + doNothing().when(WorkflowUtils.class); + Mockito.spy(PersistentWorkflowUtils.class); + doReturn(fakeWorkflow).when(PersistentWorkflowUtils.class + ); // mock external FS check when(mockCatalogService.hasRemoteFiles(eq(mockUser), any(String.class))).thenReturn(false); diff --git a/src/test/java/org/nrg/containers/QueueConsumerTest.java b/src/test/java/org/nrg/containers/QueueConsumerTest.java index 55150f6d..3517158b 100644 --- a/src/test/java/org/nrg/containers/QueueConsumerTest.java +++ b/src/test/java/org/nrg/containers/QueueConsumerTest.java @@ -9,7 +9,7 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; -import org.mockito.Mockito; +import org.mockito.MockedStatic; import org.nrg.containers.api.DockerControlApi; import org.nrg.containers.config.QueueConsumerTestConfig; import org.nrg.containers.exceptions.CommandResolutionException; @@ -22,7 +22,6 @@ import org.nrg.containers.model.xnat.FakeWorkflow; import org.nrg.containers.services.CommandResolutionService; import org.nrg.containers.services.CommandService; -import org.nrg.containers.services.ContainerEntityService; import org.nrg.containers.services.ContainerService; import org.nrg.containers.services.DockerServerService; import org.nrg.containers.utils.TestingUtils; @@ -40,10 +39,6 @@ import org.nrg.xft.security.UserI; import org.nrg.xnat.helpers.uri.UriParserUtils; import org.nrg.xnat.utils.WorkflowUtils; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.modules.junit4.PowerMockRunnerDelegate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; @@ -59,23 +54,24 @@ import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.argThat; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.when; -import static org.powermock.api.mockito.PowerMockito.doNothing; -import static org.powermock.api.mockito.PowerMockito.mockStatic; +//import static org.mockito.Mockito.*; @Slf4j -@RunWith(PowerMockRunner.class) -@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class) -@PrepareForTest({UriParserUtils.class, XFTManager.class, Users.class, WorkflowUtils.class}) -@PowerMockIgnore({"org.apache.*", "java.*", "javax.*", "org.w3c.*", "com.sun.*"}) +@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = QueueConsumerTestConfig.class) @Transactional public class QueueConsumerTest { + private MockedStatic mockedWorkflowUtils; + private MockedStatic mockedUsers; + private MockedStatic mockedXFTManager; + private MockedStatic mockedUriParserUtils; private UserI mockUser; private String buildDir; private String archiveDir; @@ -99,7 +95,6 @@ public class QueueConsumerTest { private final String REAL_IMAGE = "busybox:latest"; @Autowired private CommandService mockCommandService; - @Autowired private ContainerEntityService mockContainerEntityService; @Autowired private CommandResolutionService mockCommandResolutionService; @Autowired private ContainerService containerService; @Autowired private DockerControlApi mockDockerControlApi; @@ -120,6 +115,11 @@ public void setup() throws Exception { final String certPathEnv = System.getenv("DOCKER_CERT_PATH"); final String tlsVerify = System.getenv("DOCKER_TLS_VERIFY"); + mockedWorkflowUtils = mockStatic(WorkflowUtils.class); + mockedUsers = mockStatic(Users.class); + mockedXFTManager = mockStatic(XFTManager.class); + mockedUriParserUtils = mockStatic(UriParserUtils.class); + final boolean useTls = tlsVerify != null && tlsVerify.equals("1"); final String certPath; if (useTls) { @@ -163,18 +163,12 @@ public void setup() throws Exception { // Mock the user management service when(mockUserManagementServiceI.getUser(FAKE_USER)).thenReturn(mockUser); - // Mock UriParserUtils using PowerMock. This allows us to mock out - // the responses to its static method parseURI(). - mockStatic(UriParserUtils.class); - // Mock the aliasTokenService final AliasToken mockAliasToken = new AliasToken(); mockAliasToken.setAlias(FAKE_ALIAS); mockAliasToken.setSecret(FAKE_SECRET); when(mockAliasTokenService.issueTokenForUser(mockUser)).thenReturn(mockAliasToken); - - mockStatic(Users.class); - when(Users.getUser(FAKE_USER)).thenReturn(mockUser); + mockedUsers.when(() -> Users.getUser(FAKE_USER)).thenReturn(mockUser); // Mock the site config preferences buildDir = folder.newFolder().getAbsolutePath(); @@ -198,7 +192,7 @@ public void setup() throws Exception { .commandLine("echo hello world") .addRawInputValue(INPUT_NAME, INPUT_VALUE) .build(); - mockConfiguredCommand = Mockito.mock(ConfiguredCommand.class); + mockConfiguredCommand = mock(ConfiguredCommand.class); when(mockCommandService.getWrapper(WRAPPER_ID)).thenReturn(COMMAND_WRAPPER); when(mockCommandService.retrieveWrapper(WRAPPER_ID)).thenReturn(COMMAND_WRAPPER); when(mockCommandService.getAndConfigure(WRAPPER_ID)).thenReturn(mockConfiguredCommand); @@ -211,21 +205,20 @@ public void setup() throws Exception { mockUser, fakeWorkflow.getWorkflowId().toString() )).thenReturn(RESOLVED_COMMAND); - - // Use powermock to mock out the static method XFTManager.isInitialized() - mockStatic(XFTManager.class); - when(XFTManager.isInitialized()).thenReturn(true); - - // Also mock out workflow operations to return our fake workflow object - mockStatic(WorkflowUtils.class); - when(WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) + mockedXFTManager.when(XFTManager::isInitialized).thenReturn(true); + mockedWorkflowUtils.when(() -> WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) .thenReturn(fakeWorkflow); - doNothing().when(WorkflowUtils.class, "save", any(PersistentWorkflowI.class), isNull(EventMetaI.class)); + mockedWorkflowUtils.when(() -> WorkflowUtils.save(any(PersistentWorkflowI.class), isNull(EventMetaI.class))) + .thenAnswer(invocationOnMock -> null); } @After public void cleanup() throws Exception { fakeWorkflow = new FakeWorkflow(); + mockedUriParserUtils.closeOnDemand(); + mockedXFTManager.closeOnDemand(); + mockedUsers.closeOnDemand(); + mockedWorkflowUtils.closeOnDemand(); } @Test @@ -241,7 +234,7 @@ public void testCommandResolutionException() throws Exception { when(mockCommandResolutionService.resolve( eq(mockConfiguredCommand), argThat(TestingUtils.isMapWithEntry(INPUT_NAME, badInputValue)), - isNull(String.class), + isNull(), eq(mockUser), eq(fakeWorkflow.getWorkflowId().toString()) )).thenThrow(new CommandResolutionException(exceptionMessage)); diff --git a/src/test/java/org/nrg/containers/SwarmConstraintsIntegrationTest.java b/src/test/java/org/nrg/containers/SwarmConstraintsIntegrationTest.java index d485fbae..8ba56db5 100644 --- a/src/test/java/org/nrg/containers/SwarmConstraintsIntegrationTest.java +++ b/src/test/java/org/nrg/containers/SwarmConstraintsIntegrationTest.java @@ -4,16 +4,15 @@ import com.github.dockerjava.api.model.SwarmNode; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.SystemUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; +import org.junit.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.rules.TemporaryFolder; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.junit.runner.RunWith; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.nrg.containers.api.DockerControlApi; import org.nrg.containers.config.EventPullingIntegrationTestConfig; @@ -44,7 +43,6 @@ import org.nrg.xft.ItemI; import org.nrg.xft.XFTItem; import org.nrg.xft.event.EventDetails; -import org.nrg.xft.event.EventMetaI; import org.nrg.xft.event.persist.PersistentWorkflowI; import org.nrg.xft.event.persist.PersistentWorkflowUtils; import org.nrg.xft.schema.XFTManager; @@ -52,11 +50,6 @@ import org.nrg.xnat.helpers.uri.UriParserUtils; import org.nrg.xnat.services.archive.CatalogService; import org.nrg.xnat.utils.WorkflowUtils; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.modules.junit4.PowerMockRunnerDelegate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; @@ -64,47 +57,33 @@ import org.springframework.transaction.annotation.Transactional; import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static org.awaitility.Awaitility.await; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.either; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; import static org.nrg.containers.model.command.entity.CommandType.DOCKER_SETUP; import static org.nrg.containers.model.command.entity.CommandType.DOCKER_WRAPUP; -import static org.powermock.api.mockito.PowerMockito.doNothing; -import static org.powermock.api.mockito.PowerMockito.doReturn; -import static org.powermock.api.mockito.PowerMockito.mockStatic; @Slf4j -@RunWith(PowerMockRunner.class) -@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class) -@PrepareForTest({UriParserUtils.class, XFTManager.class, Users.class, WorkflowUtils.class, - PersistentWorkflowUtils.class, XDATServlet.class, Session.class, ContainerServicePermissionUtils.class}) -@PowerMockIgnore({"org.apache.*", "java.*", "javax.*", "org.w3c.*", "com.sun.*"}) +@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = EventPullingIntegrationTestConfig.class) @Transactional public class SwarmConstraintsIntegrationTest { + private MockedStatic mockedContainerServicePermissionUtils; + private MockedStatic mockedSession; + private MockedStatic mockedXDATServlet; + private MockedStatic mockedWorkflowUtils; + private MockedStatic mockedUsers; + private MockedStatic mockedXFTManager; + private MockedStatic mockedUriParserUtils; private UserI mockUser; private String buildDir; private String archiveDir; @@ -207,18 +186,12 @@ public void setup() throws Exception { // Mock the user management service when(mockUserManagementServiceI.getUser(FAKE_USER)).thenReturn(mockUser); - // Mock UriParserUtils using PowerMock. This allows us to mock out - // the responses to its static method parseURI(). - mockStatic(UriParserUtils.class); - // Mock the aliasTokenService final AliasToken mockAliasToken = new AliasToken(); mockAliasToken.setAlias(FAKE_ALIAS); mockAliasToken.setSecret(FAKE_SECRET); when(mockAliasTokenService.issueTokenForUser(mockUser)).thenReturn(mockAliasToken); - - mockStatic(Users.class); - when(Users.getUser(FAKE_USER)).thenReturn(mockUser); + mockedUsers.when(() -> Users.getUser(FAKE_USER)).thenReturn(mockUser); // Mock the site config preferences buildDir = folder.newFolder().getAbsolutePath(); @@ -227,34 +200,20 @@ public void setup() throws Exception { when(mockSiteConfigPreferences.getBuildPath()).thenReturn(buildDir); // transporter makes a directory under build when(mockSiteConfigPreferences.getArchivePath()).thenReturn(archiveDir); // container logs get stored under archive when(mockSiteConfigPreferences.getProperty("processingUrl", FAKE_HOST)).thenReturn(FAKE_HOST); - - // Use powermock to mock out the static method XFTManager.isInitialized() and XDATServlet.isDatabasePopulateOrUpdateCompleted() - mockStatic(XFTManager.class); - when(XFTManager.isInitialized()).thenReturn(true); - mockStatic(XDATServlet.class); - when(XDATServlet.isDatabasePopulateOrUpdateCompleted()).thenReturn(true); - - // Also mock out workflow operations to return our fake workflow object - mockStatic(WorkflowUtils.class); - when(WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) + mockedXFTManager.when(XFTManager::isInitialized).thenReturn(true); + mockedXDATServlet.when(XDATServlet::isDatabasePopulateOrUpdateCompleted).thenReturn(true); + mockedWorkflowUtils.when(() -> WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) .thenReturn(fakeWorkflow); - doNothing().when(WorkflowUtils.class, "save", Mockito.any(PersistentWorkflowI.class), isNull(EventMetaI.class)); - PowerMockito.spy(PersistentWorkflowUtils.class); - doReturn(fakeWorkflow).when(PersistentWorkflowUtils.class, "getOrCreateWorkflowData", eq(FakeWorkflow.defaultEventId), - eq(mockUser), Mockito.any(XFTItem.class), Mockito.any(EventDetails.class)); + doNothing().when(WorkflowUtils.class); + Mockito.spy(PersistentWorkflowUtils.class); + doReturn(fakeWorkflow).when(PersistentWorkflowUtils.class + ); // mock external FS check when(mockCatalogService.hasRemoteFiles(eq(mockUser), any(String.class))).thenReturn(false); - - // We can't load the XFT item in the session, so don't try - // This is only used to check the permissions, and we mock that response anyway, so we don't need a real value - mockStatic(Session.class); - when(Session.loadXnatImageSessionData(any(String.class), eq(mockUser))) + mockedSession.when(() -> Session.loadXnatImageSessionData(any(String.class), eq(mockUser))) .thenReturn(null); - - // Permissions checks - mockStatic(ContainerServicePermissionUtils.class); - when(ContainerServicePermissionUtils.canCreateOutputObject( + mockedContainerServicePermissionUtils.when(() -> ContainerServicePermissionUtils.canCreateOutputObject( eq(mockUser), any(String.class), any(XnatModelObject.class), any(Command.CommandWrapperOutput.class) )).thenReturn(true); @@ -375,6 +334,28 @@ private List setUpServerWithConstr return constraints; } + @BeforeEach + void setUpStaticMocks() { + mockedContainerServicePermissionUtils = mockStatic(ContainerServicePermissionUtils.class); + mockedSession = mockStatic(Session.class); + mockedXDATServlet = mockStatic(XDATServlet.class); + mockedWorkflowUtils = mockStatic(WorkflowUtils.class); + mockedUsers = mockStatic(Users.class); + mockedXFTManager = mockStatic(XFTManager.class); + mockedUriParserUtils = mockStatic(UriParserUtils.class); + } + + @AfterEach + void tearDownStaticMocks() { + mockedUriParserUtils.closeOnDemand(); + mockedXFTManager.closeOnDemand(); + mockedUsers.closeOnDemand(); + mockedWorkflowUtils.closeOnDemand(); + mockedXDATServlet.closeOnDemand(); + mockedSession.closeOnDemand(); + mockedContainerServicePermissionUtils.closeOnDemand(); + } + @Test @DirtiesContext public void testAlwaysRunIfNoConstraints() throws Exception { diff --git a/src/test/java/org/nrg/containers/SwarmRestartIntegrationTest.java b/src/test/java/org/nrg/containers/SwarmRestartIntegrationTest.java index 76a135d8..a3e7632b 100644 --- a/src/test/java/org/nrg/containers/SwarmRestartIntegrationTest.java +++ b/src/test/java/org/nrg/containers/SwarmRestartIntegrationTest.java @@ -5,17 +5,16 @@ import com.github.dockerjava.api.model.SwarmNodeManagerStatus; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.SystemUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; +import org.junit.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.rules.TemporaryFolder; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.junit.runner.RunWith; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.nrg.containers.api.DockerControlApi; import org.nrg.containers.config.EventPullingIntegrationTestConfig; import org.nrg.containers.model.command.auto.Command; @@ -42,7 +41,6 @@ import org.nrg.xft.ItemI; import org.nrg.xft.XFTItem; import org.nrg.xft.event.EventDetails; -import org.nrg.xft.event.EventMetaI; import org.nrg.xft.event.persist.PersistentWorkflowI; import org.nrg.xft.event.persist.PersistentWorkflowUtils; import org.nrg.xft.schema.XFTManager; @@ -50,11 +48,6 @@ import org.nrg.xnat.helpers.uri.UriParserUtils; import org.nrg.xnat.services.XnatAppInfo; import org.nrg.xnat.utils.WorkflowUtils; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.modules.junit4.PowerMockRunnerDelegate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; @@ -70,30 +63,24 @@ import java.util.concurrent.TimeUnit; import static org.awaitility.Awaitility.await; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; import static org.nrg.containers.utils.TestingUtils.BUSYBOX; -import static org.powermock.api.mockito.PowerMockito.doNothing; -import static org.powermock.api.mockito.PowerMockito.doReturn; -import static org.powermock.api.mockito.PowerMockito.mockStatic; @Slf4j -@RunWith(PowerMockRunner.class) -@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class) -@PrepareForTest({UriParserUtils.class, XFTManager.class, Users.class, WorkflowUtils.class, - PersistentWorkflowUtils.class, XDATServlet.class}) -@PowerMockIgnore({"org.apache.*", "java.*", "javax.*", "org.w3c.*", "com.sun.*"}) +@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = EventPullingIntegrationTestConfig.class) @Transactional public class SwarmRestartIntegrationTest { + private MockedStatic mockedXDATServlet; + private MockedStatic mockedWorkflowUtils; + private MockedStatic mockedUsers; + private MockedStatic mockedXFTManager; + private MockedStatic mockedUriParserUtils; private Backend backend = Backend.SWARM; private boolean swarmMode = true; @@ -154,18 +141,12 @@ public void setup() throws Exception { // Mock the user management service when(mockUserManagementServiceI.getUser(FAKE_USER)).thenReturn(mockUser); - // Mock UriParserUtils using PowerMock. This allows us to mock out - // the responses to its static method parseURI(). - mockStatic(UriParserUtils.class); - // Mock the aliasTokenService final AliasToken mockAliasToken = new AliasToken(); mockAliasToken.setAlias(FAKE_ALIAS); mockAliasToken.setSecret(FAKE_SECRET); when(mockAliasTokenService.issueTokenForUser(mockUser)).thenReturn(mockAliasToken); - - mockStatic(Users.class); - when(Users.getUser(FAKE_USER)).thenReturn(mockUser); + mockedUsers.when(() -> Users.getUser(FAKE_USER)).thenReturn(mockUser); // Mock the site config preferences buildDir = folder.newFolder().getAbsolutePath(); @@ -174,21 +155,14 @@ public void setup() throws Exception { when(mockSiteConfigPreferences.getBuildPath()).thenReturn(buildDir); // transporter makes a directory under build when(mockSiteConfigPreferences.getArchivePath()).thenReturn(archiveDir); // container logs get stored under archive when(mockSiteConfigPreferences.getProperty("processingUrl", FAKE_HOST)).thenReturn(FAKE_HOST); - - // Use powermock to mock out the static method XFTManager.isInitialized() and XDATServlet.isDatabasePopulateOrUpdateCompleted() - mockStatic(XFTManager.class); - when(XFTManager.isInitialized()).thenReturn(true); - mockStatic(XDATServlet.class); - when(XDATServlet.isDatabasePopulateOrUpdateCompleted()).thenReturn(true); - - // Also mock out workflow operations to return our fake workflow object - mockStatic(WorkflowUtils.class); - when(WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) + mockedXFTManager.when(XFTManager::isInitialized).thenReturn(true); + mockedXDATServlet.when(XDATServlet::isDatabasePopulateOrUpdateCompleted).thenReturn(true); + mockedWorkflowUtils.when(() -> WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) .thenReturn(fakeWorkflow); - doNothing().when(WorkflowUtils.class, "save", any(PersistentWorkflowI.class), isNull(EventMetaI.class)); - PowerMockito.spy(PersistentWorkflowUtils.class); - doReturn(fakeWorkflow).when(PersistentWorkflowUtils.class, "getOrCreateWorkflowData", eq(FakeWorkflow.defaultEventId), - eq(mockUser), any(XFTItem.class), any(EventDetails.class)); + doNothing().when(WorkflowUtils.class); + Mockito.spy(PersistentWorkflowUtils.class); + doReturn(fakeWorkflow).when(PersistentWorkflowUtils.class + ); // Setup docker server final BackendConfig backendConfig = TestingUtils.getBackendConfig(); @@ -229,6 +203,24 @@ public void cleanup() throws Exception { TestingUtils.cleanDockerImages(controlApi.getDockerClient(), imagesToCleanUp); } + @BeforeEach + void setUpStaticMocks() { + mockedXDATServlet = mockStatic(XDATServlet.class); + mockedWorkflowUtils = mockStatic(WorkflowUtils.class); + mockedUsers = mockStatic(Users.class); + mockedXFTManager = mockStatic(XFTManager.class); + mockedUriParserUtils = mockStatic(UriParserUtils.class); + } + + @AfterEach + void tearDownStaticMocks() { + mockedUriParserUtils.closeOnDemand(); + mockedXFTManager.closeOnDemand(); + mockedUsers.closeOnDemand(); + mockedWorkflowUtils.closeOnDemand(); + mockedXDATServlet.closeOnDemand(); + } + @Test @DirtiesContext public void testRestartShutdown() throws Exception { diff --git a/src/test/java/org/nrg/containers/api/DockerControlApiIntegrationTest.java b/src/test/java/org/nrg/containers/api/DockerControlApiIntegrationTest.java index 7dbb3001..7fa339eb 100644 --- a/src/test/java/org/nrg/containers/api/DockerControlApiIntegrationTest.java +++ b/src/test/java/org/nrg/containers/api/DockerControlApiIntegrationTest.java @@ -12,7 +12,7 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.nrg.containers.events.model.DockerContainerEvent; import org.nrg.containers.exceptions.DockerServerException; import org.nrg.containers.exceptions.NoDockerServerException; diff --git a/src/test/java/org/nrg/containers/api/DockerControlApiTest.java b/src/test/java/org/nrg/containers/api/DockerControlApiTest.java index bb079ee5..6c62bb75 100644 --- a/src/test/java/org/nrg/containers/api/DockerControlApiTest.java +++ b/src/test/java/org/nrg/containers/api/DockerControlApiTest.java @@ -14,7 +14,6 @@ import com.github.dockerjava.api.model.ServiceModeConfig; import com.github.dockerjava.api.model.ServiceSpec; import com.google.common.collect.ImmutableList; -import io.kubernetes.client.util.PatchUtils; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Rule; @@ -26,7 +25,6 @@ import org.junit.runners.Parameterized; import org.mockito.Answers; import org.mockito.ArgumentCaptor; -import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -38,12 +36,9 @@ import org.nrg.containers.services.DockerHubService; import org.nrg.containers.services.DockerServerService; import org.nrg.xft.security.UserI; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.modules.junit4.PowerMockRunnerDelegate; -import org.powermock.reflect.Whitebox; +import org.springframework.test.util.ReflectionTestUtils; +import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; @@ -56,18 +51,18 @@ import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assume.assumeThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.powermock.api.support.membermodification.MemberMatcher.method; +//import static org.powermock.api.support.membermodification.MemberMatcher.method; @Slf4j -@RunWith(PowerMockRunner.class) -@PowerMockRunnerDelegate(Parameterized.class) -@PrepareForTest({DockerControlApi.class, PatchUtils.class}) +@RunWith(Parameterized.class) public class DockerControlApiTest { final String BACKEND_ID = UUID.randomUUID().toString(); final String USER_LOGIN = UUID.randomUUID().toString(); @@ -97,17 +92,18 @@ protected void finished(Description description) { } }; - @Mock private DockerHubService dockerHubService; - @Mock private DockerServerService dockerServerService; - @Mock private KubernetesClientFactory kubernetesClientFactory; - @Mock private KubernetesClient kubernetesClient; + private DockerHubService dockerHubService = Mockito.mock(DockerHubService.class); + private DockerServerService dockerServerService = Mockito.mock(DockerServerService.class); - @Mock(answer = Answers.RETURNS_MOCKS) private com.github.dockerjava.api.DockerClient mockDockerJavaClient; - @Mock private DockerImage mockDockerImage; + private KubernetesClientFactory kubernetesClientFactory = Mockito.mock(KubernetesClientFactory.class); + private KubernetesClient kubernetesClient = Mockito.mock(KubernetesClient.class); - @Mock private DockerServer dockerServer; - @Mock private Container container; - @Mock private UserI user; + private com.github.dockerjava.api.DockerClient mockDockerJavaClient = Mockito.mock(com.github.dockerjava.api.DockerClient.class, Answers.RETURNS_MOCKS); + private DockerImage mockDockerImage = Mockito.mock(DockerImage.class); + + private DockerServer dockerServer = Mockito.mock(DockerServer.class); + private Container container = Mockito.mock(Container.class); + private UserI user = Mockito.mock(UserI.class); private DockerControlApi dockerControlApi; @@ -118,15 +114,28 @@ public void setup() throws Exception { // to use PowerMock to mock it out. // The fact that we have to do this is a code smell! // Should probably inject this client instance into DockerControlApi as a bean. - dockerControlApi = PowerMockito.spy(new DockerControlApi( + dockerControlApi = Mockito.spy(new DockerControlApi( dockerServerService, dockerHubService, kubernetesClientFactory )); - PowerMockito.doReturn(mockDockerImage) - .when(dockerControlApi, method(DockerControlApi.class, "pullImage", String.class)) - .withArguments(anyString()); - PowerMockito.doReturn(mockDockerJavaClient) - .when(dockerControlApi, method(DockerControlApi.class, "getDockerClient", DockerServer.class)) - .withArguments(dockerServer); +// Mockito.doReturn(mockDockerImage) +// .when(dockerControlApi, method(DockerControlApi.class, "pullImage", String.class)) +// .withArguments(anyString()); + + Method method = DockerControlApi.class.getDeclaredMethod("pullImage", String.class); + method.setAccessible(true); + + Mockito.doReturn(mockDockerImage) + .when(dockerControlApi) + .getClass() + .getDeclaredMethod("pullImage", String.class) + .invoke(dockerControlApi, anyString()); + +// PowerMockito.doReturn(mockDockerJavaClient) +// .when(dockerControlApi, method(DockerControlApi.class, "getDockerClient", DockerServer.class)) +// .withArguments(dockerServer); + Mockito.doReturn(mockDockerJavaClient) + .when(dockerControlApi) + .getDockerClient(any(DockerServer.class)); // Mock simple return values when(dockerServer.backend()).thenReturn(backend); @@ -160,7 +169,7 @@ public void testPing() throws Exception { case DOCKER: final PingCmd pingCmd = Mockito.mock(PingCmd.class); when(mockDockerJavaClient.pingCmd()).thenReturn(pingCmd); - when(pingCmd.exec()).thenReturn(null); + doNothing().when(pingCmd).exec(); break; case SWARM: final InspectSwarmCmd inspectSwarmCmd = Mockito.mock(InspectSwarmCmd.class); @@ -299,9 +308,18 @@ public void testCreate_container() throws Exception { // We also try to pull the image Mockito.when(mockDockerImage.tags()).thenReturn(ImmutableList.of(dockerImage)); - PowerMockito.doReturn(Collections.singletonList(mockDockerImage)) - .when(dockerControlApi, method(DockerControlApi.class, "getAllImages", DockerServer.class)) - .withArguments(dockerServer); +// Mockito.doReturn(Collections.singletonList(mockDockerImage)) +// .when(dockerControlApi, method(DockerControlApi.class, "getAllImages", DockerServer.class)) +// .withArguments(dockerServer); + + Method method = DockerControlApi.class.getDeclaredMethod("getAllImages", DockerServer.class); + method.setAccessible(true); + + Mockito.doReturn(Collections.singletonList(mockDockerImage)) + .when(dockerControlApi) + .getClass() + .getDeclaredMethod("getAllImages", DockerServer.class); + dockerControlApi.getAllImages(); } final Container expected = toLaunchAndExpectedContainerBuilder.build(); @@ -360,9 +378,14 @@ public void testCreate_resolvedCommand() throws Exception { // We also try to pull the image Mockito.when(mockDockerImage.tags()).thenReturn(ImmutableList.of(dockerImage)); - PowerMockito.doReturn(Collections.singletonList(mockDockerImage)) - .when(dockerControlApi, method(DockerControlApi.class, "getAllImages", DockerServer.class)) - .withArguments(dockerServer); + Method method = DockerControlApi.class.getDeclaredMethod("getAllImages", DockerServer.class); + method.setAccessible(true); +// doReturn(mockDockerImage).when(dockerControlApi).getAllImages(any(DockerServer.class)); +// List result = (List) method.invoke(dockerControlApi, dockerServer); + +// Mockito.doReturn(Collections.singletonList(mockDockerImage)) +// .when(dockerControlApi, method(DockerControlApi.class, "getAllImages", DockerServer.class)) +// .withArguments(dockerServer); expectedCreatedBuilder.containerId(BACKEND_ID); } @@ -411,14 +434,18 @@ public void invokeCreateDockerSwarmServicePrivateMethod(final DockerControlApi.N Mockito.when(mockDockerJavaClient.createServiceCmd(Mockito.any(ServiceSpec.class))).thenReturn(cmd); // Run the method - Whitebox.invokeMethod(dockerControlApi, "createDockerSwarmService", toCreate, dockerServer, numReplicas); +// Whitebox.invokeMethod(dockerControlApi, "createDockerSwarmService", toCreate, dockerServer, numReplicas); + Method method = DockerControlApi.class.getDeclaredMethod("createDockerSwarmService", Container.class, DockerServer.class, DockerControlApi.NumReplicas.class); + // 设置该方法可访问 + method.setAccessible(true); + method.invoke(dockerControlApi, toCreate, dockerServer, numReplicas); // Assert on results final ArgumentCaptor serviceSpecCaptor = ArgumentCaptor.forClass(ServiceSpec.class); Mockito.verify(mockDockerJavaClient).createServiceCmd(serviceSpecCaptor.capture()); final ServiceSpec serviceSpec = serviceSpecCaptor.getValue(); - assertThat(serviceSpec.getMode().getReplicated().getReplicas(), equalTo(new Integer(numReplicas.value).longValue())); + assertThat(serviceSpec.getMode().getReplicated().getReplicas(), equalTo((long) numReplicas.value)); } @Test @@ -449,12 +476,15 @@ private void testStart_swarmMode() throws Exception { final ServiceSpec serviceSpec = Mockito.mock(ServiceSpec.class); final ServiceSpec updatedSpec = Mockito.mock(ServiceSpec.class); final Service service = Mockito.mock(Service.class); + final com.github.dockerjava.api.model.ResourceVersion resourceVersion = Mockito.mock(com.github.dockerjava.api.model.ResourceVersion.class); final InspectServiceCmd inspectServiceCmd = Mockito.mock(InspectServiceCmd.class, Mockito.RETURNS_DEEP_STUBS); final UpdateServiceCmd updateServiceCmd = Mockito.mock(UpdateServiceCmd.class, Mockito.RETURNS_DEEP_STUBS); when(mockDockerJavaClient.inspectServiceCmd(BACKEND_ID)).thenReturn(inspectServiceCmd); when(mockDockerJavaClient.updateServiceCmd(BACKEND_ID, updatedSpec)).thenReturn(updateServiceCmd); when(inspectServiceCmd.exec()).thenReturn(service); when(service.getSpec()).thenReturn(serviceSpec); + when(service.getVersion()).thenReturn(resourceVersion); + when(resourceVersion.getIndex()).thenReturn(1L); when(serviceSpec.withMode(any(ServiceModeConfig.class))).thenReturn(updatedSpec); // Run the test diff --git a/src/test/java/org/nrg/containers/config/CommandTestConfig.java b/src/test/java/org/nrg/containers/config/CommandTestConfig.java index 84199840..a147c910 100644 --- a/src/test/java/org/nrg/containers/config/CommandTestConfig.java +++ b/src/test/java/org/nrg/containers/config/CommandTestConfig.java @@ -4,6 +4,7 @@ import org.nrg.containers.api.ContainerControlApi; import org.nrg.containers.services.ContainerEntityService; import org.nrg.framework.services.SerializerService; +import org.nrg.prefs.services.NrgPreferenceService; import org.nrg.xdat.preferences.SiteConfigPreferences; import org.nrg.xdat.security.services.PermissionsServiceI; import org.nrg.xdat.services.AliasTokenService; @@ -30,6 +31,11 @@ public SiteConfigPreferences siteConfigPreferences() { return Mockito.mock(SiteConfigPreferences.class); } + @Bean + public NrgPreferenceService nrgPreferenceService() { + return Mockito.mock(NrgPreferenceService.class); + } + @Bean public SerializerService serializerService() { return Mockito.mock(SerializerService.class); diff --git a/src/test/java/org/nrg/containers/config/IntegrationTestConfig.java b/src/test/java/org/nrg/containers/config/IntegrationTestConfig.java index bb7908ab..979e9603 100644 --- a/src/test/java/org/nrg/containers/config/IntegrationTestConfig.java +++ b/src/test/java/org/nrg/containers/config/IntegrationTestConfig.java @@ -62,6 +62,7 @@ import org.nrg.framework.services.NrgEventService; import org.nrg.framework.services.NrgEventServiceI; import org.nrg.mail.services.MailService; +import org.nrg.prefs.services.NrgPreferenceService; import org.nrg.xdat.preferences.SiteConfigPreferences; import org.nrg.xdat.security.services.PermissionsServiceI; import org.nrg.xdat.security.user.XnatUserProvider; @@ -94,7 +95,7 @@ @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Configuration @EnableTransactionManagement -@Import({CommandConfig.class, HibernateConfig.class, RestApiTestConfig.class}) +@Import({CommandConfig.class, HibernateConfig.class, RestApiTestConfig.class, MockJmsConfig.class}) public class IntegrationTestConfig { /* Control API and dependencies + Events @@ -341,4 +342,10 @@ public LocalSessionFactoryBean sessionFactory(final DataSource dataSource, @Qual public ResourceTransactionManager transactionManager(final SessionFactory sessionFactory) { return new HibernateTransactionManager(sessionFactory); } + + @Bean + public NrgPreferenceService nrgPreferenceService() { + return Mockito.mock(NrgPreferenceService.class); + } + } diff --git a/src/test/java/org/nrg/containers/config/JmsConfig.java b/src/test/java/org/nrg/containers/config/JmsConfig.java index 57c2ddb7..20f07328 100644 --- a/src/test/java/org/nrg/containers/config/JmsConfig.java +++ b/src/test/java/org/nrg/containers/config/JmsConfig.java @@ -99,6 +99,11 @@ public ConnectionFactory connectionFactory() { return new CachingConnectionFactory(mq); } + @Bean + public NrgPreferenceService nrgPreferenceService() { + return Mockito.mock(NrgPreferenceService.class); + } + private DefaultJmsListenerContainerFactory defaultFactory(ConnectionFactory connectionFactory, final SiteConfigPreferences siteConfigPreferences, final NotificationsPreferences notificationsPreferences, diff --git a/src/test/java/org/nrg/containers/config/LaunchRestApiTestConfig.java b/src/test/java/org/nrg/containers/config/LaunchRestApiTestConfig.java index 5955d77f..4933de73 100644 --- a/src/test/java/org/nrg/containers/config/LaunchRestApiTestConfig.java +++ b/src/test/java/org/nrg/containers/config/LaunchRestApiTestConfig.java @@ -11,6 +11,7 @@ import org.nrg.framework.services.ContextService; import org.nrg.framework.services.NrgEventServiceI; import org.nrg.framework.services.SerializerService; +import org.nrg.prefs.services.NrgPreferenceService; import org.nrg.xdat.preferences.SiteConfigPreferences; import org.nrg.xdat.security.services.PermissionsServiceI; import org.nrg.xdat.security.services.RoleHolder; @@ -83,6 +84,11 @@ public SiteConfigPreferences siteConfigPreferences() { return Mockito.mock(SiteConfigPreferences.class); } + @Bean + public NrgPreferenceService nrgPreferenceService() { + return Mockito.mock(NrgPreferenceService.class); + } + @Bean public SerializerService serializerService() { return Mockito.mock(SerializerService.class); diff --git a/src/test/java/org/nrg/containers/config/MockJmsConfig.java b/src/test/java/org/nrg/containers/config/MockJmsConfig.java index 20c528b9..c167e531 100644 --- a/src/test/java/org/nrg/containers/config/MockJmsConfig.java +++ b/src/test/java/org/nrg/containers/config/MockJmsConfig.java @@ -2,14 +2,20 @@ import org.apache.activemq.command.ActiveMQQueue; import org.mockito.Mockito; +import org.nrg.containers.jms.errors.ContainerJmsErrorHandler; import org.nrg.containers.jms.listeners.ContainerFinalizingRequestListener; import org.nrg.containers.jms.listeners.ContainerStagingRequestListener; import org.nrg.containers.jms.requests.ContainerFinalizingRequest; import org.nrg.containers.jms.requests.ContainerStagingRequest; import org.nrg.containers.services.ContainerService; +import org.nrg.mail.services.MailService; +import org.nrg.xdat.preferences.NotificationsPreferences; +import org.nrg.xdat.preferences.SiteConfigPreferences; import org.nrg.xdat.security.services.UserManagementServiceI; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Primary; import org.springframework.jms.core.BrowserCallback; import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.MessagePostProcessor; @@ -17,8 +23,8 @@ import javax.jms.Destination; import java.util.concurrent.ExecutorService; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; @@ -48,11 +54,16 @@ public Destination containerFinalizingRequest() { @SuppressWarnings("unchecked") @Bean + @Primary public JmsTemplate mockJmsTemplate(Destination containerStagingRequest, - final ContainerStagingRequestListener containerStagingRequestListener, + @Lazy final ContainerStagingRequestListener containerStagingRequestListener, Destination containerFinalizingRequest, - final ContainerFinalizingRequestListener containerFinalizingRequestListener, - ExecutorService executorService) { + @Lazy final ContainerFinalizingRequestListener containerFinalizingRequestListener, + ExecutorService executorService, + final SiteConfigPreferences siteConfigPreferences, + final NotificationsPreferences notificationsPreferences, + final MailService mailService) { + final ContainerJmsErrorHandler errorHandler = new ContainerJmsErrorHandler(siteConfigPreferences, notificationsPreferences, mailService); JmsTemplate mockJmsTemplate = Mockito.mock(JmsTemplate.class); doAnswer( invocation -> { @@ -62,7 +73,7 @@ public JmsTemplate mockJmsTemplate(Destination containerStagingRequest, try { containerStagingRequestListener.onRequest(request); } catch (Exception e) { - // ignored + errorHandler.handleError(e); } }); return null; @@ -77,7 +88,7 @@ public JmsTemplate mockJmsTemplate(Destination containerStagingRequest, try { containerFinalizingRequestListener.onRequest(request); } catch (Exception e) { - // ignored + errorHandler.handleError(e); } }); return null; diff --git a/src/test/java/org/nrg/containers/config/QueueConsumerTestConfig.java b/src/test/java/org/nrg/containers/config/QueueConsumerTestConfig.java index b9adba14..de328c17 100644 --- a/src/test/java/org/nrg/containers/config/QueueConsumerTestConfig.java +++ b/src/test/java/org/nrg/containers/config/QueueConsumerTestConfig.java @@ -33,9 +33,11 @@ import org.nrg.framework.services.NrgEventServiceI; import org.nrg.mail.services.MailService; import org.nrg.mail.services.impl.SpringBasedMailServiceImpl; +import org.nrg.prefs.services.NrgPreferenceService; import org.nrg.xdat.preferences.SiteConfigPreferences; import org.nrg.xdat.security.services.PermissionsServiceI; import org.nrg.xdat.services.AliasTokenService; +import org.nrg.xdat.services.cache.UserDataCache; import org.nrg.xnat.services.XnatAppInfo; import org.nrg.xnat.services.archive.CatalogService; import org.springframework.beans.factory.annotation.Qualifier; @@ -198,6 +200,11 @@ public SiteConfigPreferences siteConfigPreferences() { return Mockito.mock(SiteConfigPreferences.class); } + @Bean + public NrgPreferenceService fakePrefsService() { + return Mockito.mock(NrgPreferenceService.class); + } + @Bean public ConfigService configService() { return Mockito.mock(ConfigService.class); diff --git a/src/test/java/org/nrg/containers/config/RestApiTestConfig.java b/src/test/java/org/nrg/containers/config/RestApiTestConfig.java index e3794147..8caf439c 100644 --- a/src/test/java/org/nrg/containers/config/RestApiTestConfig.java +++ b/src/test/java/org/nrg/containers/config/RestApiTestConfig.java @@ -23,7 +23,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import static org.powermock.api.mockito.PowerMockito.when; +import static org.mockito.Mockito.when; @Configuration @Import({ObjectMapperConfig.class}) diff --git a/src/test/java/org/nrg/containers/jms/JmsConsumerExceptionTest.java b/src/test/java/org/nrg/containers/jms/JmsConsumerExceptionTest.java index ba10be2b..97760d2d 100644 --- a/src/test/java/org/nrg/containers/jms/JmsConsumerExceptionTest.java +++ b/src/test/java/org/nrg/containers/jms/JmsConsumerExceptionTest.java @@ -1,9 +1,11 @@ package org.nrg.containers.jms; import lombok.extern.slf4j.Slf4j; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.nrg.containers.config.IntegrationTestConfig; import org.nrg.containers.config.JmsConfig; @@ -14,6 +16,7 @@ import org.nrg.containers.utils.TestingUtils; import org.nrg.mail.services.MailService; import org.nrg.xdat.entities.AliasToken; +import org.nrg.xdat.preferences.NotificationsPreferences; import org.nrg.xdat.preferences.SiteConfigPreferences; import org.nrg.xdat.security.helpers.Users; import org.nrg.xdat.security.services.PermissionsServiceI; @@ -22,7 +25,6 @@ import org.nrg.xft.ItemI; import org.nrg.xft.XFTItem; import org.nrg.xft.event.EventDetails; -import org.nrg.xft.event.EventMetaI; import org.nrg.xft.event.persist.PersistentWorkflowI; import org.nrg.xft.event.persist.PersistentWorkflowUtils; import org.nrg.xft.schema.XFTManager; @@ -30,11 +32,6 @@ import org.nrg.xnat.helpers.uri.UriParserUtils; import org.nrg.xnat.services.archive.CatalogService; import org.nrg.xnat.utils.WorkflowUtils; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.modules.junit4.PowerMockRunnerDelegate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; @@ -43,24 +40,25 @@ import java.util.Collections; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.contains; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.contains; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.when; -import static org.powermock.api.mockito.PowerMockito.mockStatic; @Slf4j -@RunWith(PowerMockRunner.class) -@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class) -@PrepareForTest({UriParserUtils.class, XFTManager.class, Users.class, WorkflowUtils.class, - PersistentWorkflowUtils.class}) -@PowerMockIgnore({"org.apache.*", "java.*", "javax.*", "org.w3c.*", "com.sun.*"}) +@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {JmsConfig.class, IntegrationTestConfig.class}) @Transactional public class JmsConsumerExceptionTest { + private MockedStatic mockedWorkflowUtils; + private MockedStatic mockedUsers; + private MockedStatic mockedXFTManager; + private MockedStatic mockedUriParserUtils; + private MockedStatic mockedPersistentWorkflowUtils; + @Autowired private SiteConfigPreferences mockSiteConfigPreferences; @Autowired private UserManagementServiceI mockUserManagementServiceI; @Autowired private PermissionsServiceI mockPermissionsServiceI; @@ -69,6 +67,7 @@ public class JmsConsumerExceptionTest { @Autowired private ContainerService containerService; @Autowired private MailService mockMailService; @Autowired private AliasTokenService mockAliasTokenService; + @Autowired private NotificationsPreferences mockNotificationsPreferences; private UserI mockUser; private FakeWorkflow fakeWorkflow; @@ -83,11 +82,19 @@ public class JmsConsumerExceptionTest { public void setup() throws Exception { fakeWorkflow = new FakeWorkflow(); + mockedWorkflowUtils = Mockito.mockStatic(WorkflowUtils.class); + mockedUsers = mockStatic(Users.class); + mockedXFTManager = Mockito.mockStatic(XFTManager.class); + mockedUriParserUtils = Mockito.mockStatic(UriParserUtils.class); + mockedPersistentWorkflowUtils = Mockito.mockStatic(PersistentWorkflowUtils.class); + mockUser = mock(UserI.class); when(mockUser.getLogin()).thenReturn(FAKE_USER); when(mockUser.getEmail()).thenReturn(FAKE_EMAIL); - mockStatic(Users.class); - when(Users.getUser(FAKE_USER)).thenReturn(mockUser); + +// mockStatic(Users.class); +// when(Users.getUser(FAKE_USER)).thenReturn(mockUser); + mockedUsers.when(() -> Users.getUser(FAKE_USER)).thenReturn(mockUser); // Mock the site config preferences when(mockSiteConfigPreferences.getProperty("processingUrl", FAKE_HOST)).thenReturn(FAKE_HOST); @@ -95,6 +102,9 @@ public void setup() throws Exception { when(mockSiteConfigPreferences.getSiteId()).thenReturn(FAKE_SITEID); when(mockSiteConfigPreferences.getAdminEmail()).thenReturn(FAKE_EMAIL); + // Mock notifications preferences to allow JMS error notifications + when(mockNotificationsPreferences.getSuppressJMSFailureNotifications()).thenReturn(false); + // Permissions when(mockPermissionsServiceI.canEdit(any(UserI.class), any(ItemI.class))).thenReturn(Boolean.TRUE); @@ -107,22 +117,29 @@ public void setup() throws Exception { mockAliasToken.setSecret("secret"); when(mockAliasTokenService.issueTokenForUser(mockUser)).thenReturn(mockAliasToken); - // Mock UriParserUtils using PowerMock. This allows us to mock out - // the responses to its static method parseURI(). - PowerMockito.mockStatic(UriParserUtils.class); - // Use powermock to mock out the static method XFTManager.isInitialized() - PowerMockito.mockStatic(XFTManager.class); - when(XFTManager.isInitialized()).thenReturn(true); +// PowerMockito.mockStatic(XFTManager.class); +// when(XFTManager.isInitialized()).thenReturn(true); + mockedXFTManager.when(XFTManager::isInitialized).thenReturn(true); // Also mock out workflow operations to return our fake workflow object - PowerMockito.mockStatic(WorkflowUtils.class); - when(WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) +// PowerMockito.mockStatic(WorkflowUtils.class); +// when(WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) + mockedWorkflowUtils.when(() -> WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) + .thenReturn(fakeWorkflow); + +// PowerMockito.doNothing().when(WorkflowUtils.class, "save", any(PersistentWorkflowI.class), isNull(EventMetaI.class)); + mockedWorkflowUtils.when(() -> WorkflowUtils.save(Mockito.any(), Mockito.isNull())).thenAnswer(invocation -> null); + +// PowerMockito.spy(PersistentWorkflowUtils.class); +// PowerMockito.doReturn(fakeWorkflow).when(PersistentWorkflowUtils.class, "getOrCreateWorkflowData", eq(FakeWorkflow.defaultEventId), +// eq(mockUser), any(XFTItem.class), any(EventDetails.class)); + mockedPersistentWorkflowUtils.when(() -> PersistentWorkflowUtils.getOrCreateWorkflowData( + eq(FakeWorkflow.defaultEventId), eq(mockUser), any(XFTItem.class), any(EventDetails.class))) .thenReturn(fakeWorkflow); - PowerMockito.doNothing().when(WorkflowUtils.class, "save", any(PersistentWorkflowI.class), isNull(EventMetaI.class)); - PowerMockito.spy(PersistentWorkflowUtils.class); - PowerMockito.doReturn(fakeWorkflow).when(PersistentWorkflowUtils.class, "getOrCreateWorkflowData", eq(FakeWorkflow.defaultEventId), - eq(mockUser), any(XFTItem.class), any(EventDetails.class)); + + PersistentWorkflowUtils.getOrCreateWorkflowData( + FakeWorkflow.defaultEventId, mockUser, Mockito.mock(XFTItem.class), Mockito.mock(EventDetails.class)); // mock external FS check when(mockCatalogService.hasRemoteFiles(eq(mockUser), any(String.class))).thenReturn(false); @@ -137,27 +154,44 @@ public void setup() throws Exception { .name("placeholder") .build()) .build()); - wrapper = command.xnatCommandWrappers().get(0); + wrapper = command.xnatCommandWrappers().getFirst(); TestingUtils.commitTransaction(); fakeWorkflow.setId(FAKE_ID); fakeWorkflow.setPipelineName(wrapper.name()); } + @After + public void tearDownStaticMocks() { + mockedUriParserUtils.closeOnDemand(); + mockedXFTManager.closeOnDemand(); + mockedUsers.closeOnDemand(); + mockedWorkflowUtils.closeOnDemand(); + } + @Test @DirtiesContext //CS-1031 public void testStagingConsumeFailure() throws Exception { - // setup jmsTemplate to throw exception + // Setup: Make userManagementServiceI throw a RuntimeException that won't be caught by the listener + // This will propagate to the JMS error handler, unlike exceptions thrown from within + // consumeResolveCommandAndLaunchContainer which are caught internally String exceptionMsg = "my tricky exception message"; - PowerMockito.when(WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) + + // Reset the user management mock to throw an uncaught exception + Mockito.reset(mockUserManagementServiceI); + when(mockUserManagementServiceI.getUser(FAKE_USER)) .thenThrow(new RuntimeException(exceptionMsg)); - containerService.queueResolveCommandAndLaunchContainer(null, wrapper.id(), 0L, wrapper.name(), Collections.emptyMap(), mockUser, fakeWorkflow - ); + containerService.queueResolveCommandAndLaunchContainer(null, wrapper.id(), 0L, wrapper.name(), + Collections.emptyMap(), mockUser, fakeWorkflow); - Mockito.verify(mockMailService, timeout(500).times(1)).sendHtmlMessage(eq(FAKE_EMAIL), - eq(FAKE_EMAIL), eq(FAKE_SITEID + " JMS Error"), contains(exceptionMsg)); + // Verify that the error handler sends an email notification + Mockito.verify(mockMailService, timeout(5000).times(1)).sendHtmlMessage( + eq(FAKE_EMAIL), + eq(FAKE_EMAIL), + eq(FAKE_SITEID + " JMS Error"), + contains(exceptionMsg)); } } diff --git a/src/test/java/org/nrg/containers/jms/JmsExceptionIntegrationTest.java b/src/test/java/org/nrg/containers/jms/JmsExceptionIntegrationTest.java index 57ba7e69..4c2d0fc3 100644 --- a/src/test/java/org/nrg/containers/jms/JmsExceptionIntegrationTest.java +++ b/src/test/java/org/nrg/containers/jms/JmsExceptionIntegrationTest.java @@ -5,9 +5,12 @@ import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; -import org.mockito.Matchers; +import org.mockito.ArgumentMatchers; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.nrg.containers.api.DockerControlApi; import org.nrg.containers.config.EventPullingIntegrationTestConfig; @@ -28,7 +31,6 @@ import org.nrg.xft.ItemI; import org.nrg.xft.XFTItem; import org.nrg.xft.event.EventDetails; -import org.nrg.xft.event.EventMetaI; import org.nrg.xft.event.persist.PersistentWorkflowI; import org.nrg.xft.event.persist.PersistentWorkflowUtils; import org.nrg.xft.schema.XFTManager; @@ -36,11 +38,6 @@ import org.nrg.xnat.helpers.uri.UriParserUtils; import org.nrg.xnat.services.archive.CatalogService; import org.nrg.xnat.utils.WorkflowUtils; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.modules.junit4.PowerMockRunnerDelegate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.MessagePostProcessor; @@ -59,24 +56,18 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.mockito.AdditionalMatchers.aryEq; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyMapOf; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.when; -import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; @Slf4j -@RunWith(PowerMockRunner.class) -@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class) -@PrepareForTest({UriParserUtils.class, XFTManager.class, Users.class, WorkflowUtils.class, - PersistentWorkflowUtils.class}) -@PowerMockIgnore({"org.apache.*", "java.*", "javax.*", "org.w3c.*", "com.sun.*"}) +@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = EventPullingIntegrationTestConfig.class) @Transactional public class JmsExceptionIntegrationTest { + private MockedStatic mockedWorkflowUtils; + private MockedStatic mockedUsers; + private MockedStatic mockedXFTManager; + private MockedStatic mockedUriParserUtils; @Autowired private JmsTemplate mockJmsTemplate; @Autowired private SiteConfigPreferences mockSiteConfigPreferences; @Autowired private UserManagementServiceI mockUserManagementServiceI; @@ -119,8 +110,7 @@ public void setup() throws Exception { mockUser = mock(UserI.class); when(mockUser.getLogin()).thenReturn(FAKE_USER); when(mockUser.getEmail()).thenReturn(FAKE_EMAIL); - mockStatic(Users.class); - when(Users.getUser(FAKE_USER)).thenReturn(mockUser); + mockedUsers.when(() -> Users.getUser(FAKE_USER)).thenReturn(mockUser); // Mock the site config preferences String buildDir = folder.newFolder().getAbsolutePath(); @@ -143,23 +133,12 @@ public void setup() throws Exception { mockAliasToken.setAlias("alias"); mockAliasToken.setSecret("secret"); when(mockAliasTokenService.issueTokenForUser(mockUser)).thenReturn(mockAliasToken); - - // Mock UriParserUtils using PowerMock. This allows us to mock out - // the responses to its static method parseURI(). - PowerMockito.mockStatic(UriParserUtils.class); - - // Use powermock to mock out the static method XFTManager.isInitialized() - PowerMockito.mockStatic(XFTManager.class); - when(XFTManager.isInitialized()).thenReturn(true); - - // Also mock out workflow operations to return our fake workflow object - PowerMockito.mockStatic(WorkflowUtils.class); - when(WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) + mockedXFTManager.when(XFTManager::isInitialized).thenReturn(true); + mockedWorkflowUtils.when(() -> WorkflowUtils.getUniqueWorkflow(mockUser, fakeWorkflow.getWorkflowId().toString())) .thenReturn(fakeWorkflow); - PowerMockito.doNothing().when(WorkflowUtils.class, "save", any(PersistentWorkflowI.class), isNull(EventMetaI.class)); - PowerMockito.spy(PersistentWorkflowUtils.class); - PowerMockito.doReturn(fakeWorkflow).when(PersistentWorkflowUtils.class, "getOrCreateWorkflowData", eq(FakeWorkflow.defaultEventId), - eq(mockUser), any(XFTItem.class), any(EventDetails.class)); + Mockito.doNothing().when(WorkflowUtils.class); + Mockito.spy(PersistentWorkflowUtils.class); + Mockito.doReturn(fakeWorkflow).when(PersistentWorkflowUtils.class); // mock external FS check when(mockCatalogService.hasRemoteFiles(eq(mockUser), any(String.class))).thenReturn(false); @@ -181,6 +160,22 @@ public void setup() throws Exception { fakeWorkflow.setPipelineName(wrapper.name()); } + @BeforeEach + void setUpStaticMocks() { + mockedWorkflowUtils = Mockito.mockStatic(WorkflowUtils.class); + mockedUsers = mockStatic(Users.class); + mockedXFTManager = Mockito.mockStatic(XFTManager.class); + mockedUriParserUtils = Mockito.mockStatic(UriParserUtils.class); + } + + @AfterEach + void tearDownStaticMocks() { + mockedUriParserUtils.closeOnDemand(); + mockedXFTManager.closeOnDemand(); + mockedUsers.closeOnDemand(); + mockedWorkflowUtils.closeOnDemand(); + } + @Test @DirtiesContext public void testStagingQueueFailure() throws Exception { @@ -196,10 +191,10 @@ public void testStagingQueueFailure() throws Exception { assertThat(fakeWorkflow.getDetails(), is(exceptionMsg)); Mockito.verify(mockMailService, times(1)).sendHtmlMessage(eq(FAKE_EMAIL), - aryEq(new String[]{FAKE_EMAIL}), aryEq(new String[]{FAKE_EMAIL}), Matchers.eq(null), + aryEq(new String[]{FAKE_EMAIL}), aryEq(new String[]{FAKE_EMAIL}), ArgumentMatchers.eq(null), Mockito.matches(".*" + wrapper.name() + ".*Failed.*"), Mockito.matches(".*" + wrapper.name() + ".*" + FAKE_ID + ".*failed.*"), Mockito.matches(".*" + wrapper.name() + ".*" + FAKE_ID + ".*failed.*"), - anyMapOf(String.class, File.class)); + anyMap()); } } diff --git a/src/test/java/org/nrg/containers/model/CommandConfigurationTest.java b/src/test/java/org/nrg/containers/model/CommandConfigurationTest.java index ffaf078c..8ff5fca1 100644 --- a/src/test/java/org/nrg/containers/model/CommandConfigurationTest.java +++ b/src/test/java/org/nrg/containers/model/CommandConfigurationTest.java @@ -23,10 +23,10 @@ import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isNotNull; -import static org.mockito.Matchers.isNull; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNotNull; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.when; import static org.nrg.containers.services.ContainerConfigService.TOOL_ID; @@ -56,7 +56,7 @@ public void testConfigureCommandForSite() throws Exception { final Configuration mockSiteConfiguration = Mockito.mock(Configuration.class); when(mockSiteConfiguration.getContents()).thenReturn(siteJson); - when(mockConfigService.getConfig(eq(TOOL_ID), anyString(), eq(Scope.Site), isNull(String.class))).thenReturn(mockSiteConfiguration); + when(mockConfigService.getConfig(eq(TOOL_ID), anyString(), eq(Scope.Site), isNull())).thenReturn(mockSiteConfiguration); final CommandConfigurationInternal retrieved = containerConfigService.getSiteConfiguration(WRAPPER_ID); assertThat(retrieved, is(site)); @@ -132,7 +132,7 @@ public void testConfigureCommandForProject() throws Exception { final Configuration mockSiteConfiguration = Mockito.mock(Configuration.class); when(mockSiteConfiguration.getContents()).thenReturn(siteJson); - when(mockConfigService.getConfig(eq(TOOL_ID), anyString(), eq(Scope.Site), isNull(String.class))).thenReturn(mockSiteConfiguration); + when(mockConfigService.getConfig(eq(TOOL_ID), anyString(), eq(Scope.Site), isNull())).thenReturn(mockSiteConfiguration); final Configuration mockProjectConfiguration = Mockito.mock(Configuration.class); when(mockProjectConfiguration.getContents()).thenReturn(projectJson); when(mockConfigService.getConfig(eq(TOOL_ID), anyString(), eq(Scope.Project), isNotNull(String.class))).thenReturn(mockProjectConfiguration); diff --git a/src/test/java/org/nrg/containers/rest/CommandConfigurationRestApiTest.java b/src/test/java/org/nrg/containers/rest/CommandConfigurationRestApiTest.java index deaf2284..98ae3952 100644 --- a/src/test/java/org/nrg/containers/rest/CommandConfigurationRestApiTest.java +++ b/src/test/java/org/nrg/containers/rest/CommandConfigurationRestApiTest.java @@ -39,9 +39,9 @@ import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isNull; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -190,7 +190,7 @@ public void testCreateSiteConfig() throws Exception { eq(configPath), eq(commandConfigurationInternalJson), eq(Scope.Site), - isNull(String.class))) + isNull())) .thenReturn(null); final MockHttpServletRequestBuilder request = @@ -212,7 +212,7 @@ public void testGetSiteConfig() throws Exception { eq(ContainerConfigService.TOOL_ID), eq(configPath), eq(Scope.Site), - isNull(String.class) + isNull() )) .thenReturn(mockConfig); @@ -240,7 +240,7 @@ public void testDeleteSiteConfig() throws Exception { eq(ContainerConfigService.TOOL_ID), eq(configPath), eq(Scope.Site), - isNull(String.class) + isNull() )) .thenReturn(mockConfig); doNothing().when(mockConfigService).delete(mockConfig); @@ -337,7 +337,7 @@ public void testEnableForSite() throws Exception { eq(ContainerConfigService.TOOL_ID), eq(configPath), eq(Scope.Site), - isNull(String.class) + isNull() )) .thenReturn(mockConfig); @@ -367,7 +367,7 @@ public void testDisableForSite() throws Exception { eq(ContainerConfigService.TOOL_ID), eq(configPath), eq(Scope.Site), - isNull(String.class) + isNull() )) .thenReturn(mockConfig); diff --git a/src/test/java/org/nrg/containers/rest/CommandRestApiTest.java b/src/test/java/org/nrg/containers/rest/CommandRestApiTest.java index 921692e9..a200617f 100644 --- a/src/test/java/org/nrg/containers/rest/CommandRestApiTest.java +++ b/src/test/java/org/nrg/containers/rest/CommandRestApiTest.java @@ -28,7 +28,6 @@ import org.nrg.xdat.security.services.UserManagementServiceI; import org.nrg.xdat.services.AliasTokenService; import org.nrg.xft.security.UserI; -import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.security.authentication.TestingAuthenticationToken; @@ -71,7 +70,6 @@ @Slf4j @RunWith(SpringJUnit4ClassRunner.class) -@PowerMockIgnore({"org.apache.*", "java.*", "javax.*", "org.w3c.*", "com.sun.*"}) @WebAppConfiguration @Transactional @ContextConfiguration(classes = CommandRestApiTestConfig.class) diff --git a/src/test/java/org/nrg/containers/rest/ContainerRestApiTest.java b/src/test/java/org/nrg/containers/rest/ContainerRestApiTest.java index 7e47b206..01016fec 100644 --- a/src/test/java/org/nrg/containers/rest/ContainerRestApiTest.java +++ b/src/test/java/org/nrg/containers/rest/ContainerRestApiTest.java @@ -6,6 +6,8 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.nrg.containers.config.ContainerRestApiTestConfig; @@ -14,14 +16,9 @@ import org.nrg.containers.model.server.docker.Backend; import org.nrg.containers.services.ContainerEntityService; import org.nrg.containers.services.ContainerService; -import org.nrg.xdat.security.helpers.Permissions; import org.nrg.xdat.security.services.RoleServiceI; import org.nrg.xdat.security.services.UserManagementServiceI; import org.nrg.xft.security.UserI; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.modules.junit4.PowerMockRunnerDelegate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.security.authentication.TestingAuthenticationToken; @@ -41,26 +38,16 @@ import java.util.Set; import java.util.stream.Collectors; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.testSecurityContext; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -@RunWith(PowerMockRunner.class) -@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class) -@PrepareForTest({Permissions.class}) -@PowerMockIgnore({"org.apache.*", "java.*", "javax.*", "org.w3c.*", "com.sun.*"}) +@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @Transactional @ContextConfiguration(classes = ContainerRestApiTestConfig.class) @@ -125,6 +112,14 @@ public void setup() throws Exception { } } + @BeforeEach + void setUpStaticMocks() { + } + + @AfterEach + void tearDownStaticMocks() { + } + @Test public void testSpringConfiguration() { assertThat(containerService, not(nullValue())); diff --git a/src/test/java/org/nrg/containers/rest/LaunchRestApiTest.java b/src/test/java/org/nrg/containers/rest/LaunchRestApiTest.java index 167a7c2e..6293804a 100644 --- a/src/test/java/org/nrg/containers/rest/LaunchRestApiTest.java +++ b/src/test/java/org/nrg/containers/rest/LaunchRestApiTest.java @@ -51,11 +51,12 @@ import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyMapOf; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; import static org.nrg.containers.model.server.docker.DockerServerBase.DockerServer; @@ -97,7 +98,7 @@ public class LaunchRestApiTest { private CommandWrapper COMMAND_WRAPPER; private ResolvedCommand RESOLVED_COMMAND; - private final MediaType JSON = MediaType.APPLICATION_JSON_UTF8; + private final MediaType JSON = MediaType.APPLICATION_JSON; private final MediaType XML = MediaType.APPLICATION_XML; @Autowired private WebApplicationContext wac; @@ -185,7 +186,7 @@ public void setup() throws Exception { // Mock queuing when(mockContainerService.createContainerWorkflow(eq(FAKE_XNAT_ID), eq(FAKE_ROOT), eq(WRAPPER_NAME), - eq(""), eq(mockAdmin), any(String.class), any(Long.class), anyInt())) + eq(""), eq(mockAdmin), any(String.class), anyLong(), anyInt())) .thenReturn(mockWorkflow); // We have to match any resolved command because spring will add a csrf token to the inputs. I don't know how to get that token in advance. @@ -204,8 +205,8 @@ public void testLaunchWithQueryParams() throws Exception { ); when(mockContainerService.launchContainer( - anyString(), any(Long.class), anyString(), eq(WRAPPER_ID), eq(FAKE_ROOT), - anyMapOf(String.class, String.class), any(UserI.class)) + any(), anyLong(), any(), eq(WRAPPER_ID), eq(FAKE_ROOT), + any(Map.class), any(UserI.class)) ).thenReturn(report); final String path = String.format(pathTemplate, WRAPPER_ID, FAKE_ROOT); @@ -231,8 +232,8 @@ public void testLaunchWithParamsInBody() throws Exception { ); when(mockContainerService.launchContainer( - any(String.class), any(Long.class), any(String.class), eq(WRAPPER_ID), eq(FAKE_ROOT), - anyMapOf(String.class, String.class), any(UserI.class)) + any(), anyLong(), any(), eq(WRAPPER_ID), eq(FAKE_ROOT), + any(Map.class), any(UserI.class)) ).thenReturn(report); final String path = String.format(pathTemplate, WRAPPER_ID, FAKE_ROOT); @@ -275,8 +276,8 @@ public void testBulkLaunch() throws Exception { .build(); when(mockContainerService.bulkLaunch( - any(String.class), any(Long.class), any(String.class), eq(WRAPPER_ID), eq(FAKE_ROOT), - anyMapOf(String.class, String.class), any(UserI.class) + any(), anyLong(), any(), eq(WRAPPER_ID), eq(FAKE_ROOT), + anyMap(), any(UserI.class) )).thenReturn(report); //final String exceptionMessage = "Unable to queue container launch"; @@ -326,7 +327,7 @@ public void testGetLaunchUI() throws Exception { .commandName(COMMAND_NAME) .image(IMAGE) .build(); - when(mockCommandResolutionService.preResolve(eq(project), any(long.class), any(String.class), eq(WRAPPER_ID), anyMapOf(String.class, String.class), eq(mockAdmin))) + when(mockCommandResolutionService.preResolve(eq(project), anyLong(), any(), eq(WRAPPER_ID), anyMap(), eq(mockAdmin))) .thenReturn(partiallyResolvedCommand); final LaunchUi expectedLaunchUi = LaunchUi.create(partiallyResolvedCommand, diff --git a/src/test/java/org/nrg/containers/secrets/SecretsTest.java b/src/test/java/org/nrg/containers/secrets/SecretsTest.java index d4e1458b..27b48113 100644 --- a/src/test/java/org/nrg/containers/secrets/SecretsTest.java +++ b/src/test/java/org/nrg/containers/secrets/SecretsTest.java @@ -25,11 +25,9 @@ import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; -import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.Mock; +import org.mockito.InjectMocks; import org.mockito.Mockito; -import org.mockito.internal.util.reflection.Whitebox; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.nrg.containers.api.DockerControlApi; @@ -51,11 +49,10 @@ import org.nrg.xdat.services.cache.UserDataCache; import org.nrg.xft.security.UserI; import org.nrg.xnat.services.archive.CatalogService; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest; -import org.powermock.modules.junit4.PowerMockRunner; import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.AbstractMap; import java.util.Collections; import java.util.List; @@ -75,24 +72,27 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; @Slf4j -@RunWith(PowerMockRunner.class) -@PrepareOnlyThisForTest(DockerControlApi.class) +//@PrepareOnlyThisForTest(DockerControlApi.class) public class SecretsTest { private final static Answer RETURN_SELF = InvocationOnMock::getMock; - @Mock private SystemPropertySecretSource.ValueObtainer valueObtainer; - @Mock private CommandService commandService; - @Mock private DockerServerService dockerServerService; - @Mock private SiteConfigPreferences siteConfigPreferences; - @Mock private DockerService dockerService; - @Mock private CatalogService catalogService; - @Mock private UserDataCache userDataCache; - @Mock private KubernetesClientImpl kubernetesClient; - @Mock private DockerServerBase.DockerServer dockerServer; - - @Mock private UserI user; + private SystemPropertySecretSource.ValueObtainer valueObtainer = Mockito.mock(SystemPropertySecretSource.ValueObtainer.class); + private CommandService commandService = Mockito.mock(CommandService.class); + private DockerServerService dockerServerService = Mockito.mock(DockerServerService.class); + private SiteConfigPreferences siteConfigPreferences = Mockito.mock(SiteConfigPreferences.class); + private DockerService dockerService = Mockito.mock(DockerService.class); + private CatalogService catalogService =Mockito.mock(CatalogService.class); + private UserDataCache userDataCache = Mockito.mock(UserDataCache.class); + private KubernetesClientImpl kubernetesClient = Mockito.mock(KubernetesClientImpl.class); + private DockerServerBase.DockerServer dockerServer = Mockito.mock(DockerServerBase.DockerServer.class); + private org.nrg.containers.services.DockerHubService dockerHubService = Mockito.mock(org.nrg.containers.services.DockerHubService.class); + private org.nrg.containers.api.KubernetesClientFactory kubernetesClientFactory = Mockito.mock(org.nrg.containers.api.KubernetesClientFactory.class); + + private UserI user = Mockito.mock(UserI.class); private Backend backend = null; private String userId; @@ -224,10 +224,17 @@ public void testLaunchKubernetesJobWithEnvSecret() throws Exception { backend = Backend.KUBERNETES; final String namespace = RandomStringUtils.randomAlphabetic(5); - Whitebox.setInternalState(kubernetesClient, "namespace", namespace); + // Whitebox.setInternalState(kubernetesClient, "namespace", namespace); + Field namespaceField = kubernetesClient.getClass().getDeclaredField("namespace"); + namespaceField.setAccessible(true); // Allow access to private fields + namespaceField.set(kubernetesClient, namespace); final BatchV1Api batchApi = Mockito.mock(BatchV1Api.class); - Whitebox.setInternalState(kubernetesClient, "batchApi", batchApi); + // Whitebox.setInternalState(kubernetesClient, "batchApi", batchApi); + Field batchApiField = kubernetesClient.getClass().getDeclaredField("batchApi"); + batchApiField.setAccessible(true); // Allow access to private fields + batchApiField.set(kubernetesClient, batchApi); + // Create secret value and objects final String secretValue = RandomStringUtils.randomAlphanumeric(32); @@ -255,8 +262,8 @@ public void testLaunchKubernetesJobWithEnvSecret() throws Exception { // In real life the backend would return the job spec we sent in + a bunch of info about what got created. // But we don't need any of that extra stuff, we only want to see the spec we made. // We return exactly the same job spec we sent in, as if the backend responded after having done nothing at all. - Mockito.when(batchApi.createNamespacedJob(Mockito.eq(namespace), Mockito.any(V1Job.class), Mockito.isNull(String.class), Mockito.isNull(String.class), Mockito.isNull(String.class), Mockito.isNull(String.class))) - .thenAnswer((Answer) invocation -> invocation.getArgumentAt(1, V1Job.class)); + Mockito.when(batchApi.createNamespacedJob(Mockito.eq(namespace), Mockito.any(V1Job.class), Mockito.isNull(), Mockito.isNull(), Mockito.isNull(), Mockito.isNull())) + .thenAnswer((Answer) invocation -> invocation.getArgument(1, V1Job.class)); // Call method under test Mockito.when(kubernetesClient.createJob(toCreate, DockerControlApi.NumReplicas.ZERO, null, null, null)) @@ -265,7 +272,7 @@ public void testLaunchKubernetesJobWithEnvSecret() throws Exception { // Capture call to backend api mock final ArgumentCaptor jobArgumentCaptor = ArgumentCaptor.forClass(V1Job.class); - Mockito.verify(batchApi).createNamespacedJob(Mockito.eq(namespace), jobArgumentCaptor.capture(), Mockito.isNull(String.class), Mockito.isNull(String.class), Mockito.isNull(String.class), Mockito.isNull(String.class)); + Mockito.verify(batchApi).createNamespacedJob(Mockito.eq(namespace), jobArgumentCaptor.capture(), Mockito.isNull(), Mockito.isNull(), Mockito.isNull(), Mockito.isNull()); final V1Job job = jobArgumentCaptor.getValue(); // Extract container spec @@ -315,13 +322,25 @@ public void testLaunchSwarmJobWithEnvSecret() throws Exception { .build(); // Class under test - final DockerControlApi dockerControlApi = PowerMockito.mock(DockerControlApi.class); + final DockerControlApi dockerControlApi = Mockito.spy(new DockerControlApi(dockerServerService, dockerHubService, kubernetesClientFactory)); // Mock out DockerControlApi#getDockerClient(dockerServer) final DockerClient dockerClient = Mockito.mock(DockerClient.class); - PowerMockito.doReturn(dockerClient).when(dockerControlApi, "getDockerClient", dockerServer); - - PowerMockito.doReturn(dockerServer).when(dockerControlApi, "getServer"); +// PowerMockito.doReturn(dockerClient).when(dockerControlApi, "getDockerClient", dockerServer); + Mockito.doReturn(dockerClient).when(dockerControlApi) + .getDockerClient(any(DockerServerBase.DockerServer.class)); + + // PowerMockito.doReturn(dockerServer).when(dockerControlApi, "getServer"); + when(dockerServerService.getServer()).thenReturn(dockerServer); + + // Mock authConfig - return a valid DockerHub so authConfig doesn't need to access config + final org.nrg.containers.model.dockerhub.DockerHubBase.DockerHub mockDockerHub = Mockito.mock(org.nrg.containers.model.dockerhub.DockerHubBase.DockerHub.class); + when(mockDockerHub.url()).thenReturn("docker.io"); + when(mockDockerHub.username()).thenReturn(""); + when(mockDockerHub.password()).thenReturn(""); + when(mockDockerHub.token()).thenReturn(""); + when(mockDockerHub.email()).thenReturn(""); + when(dockerHubService.getByUrl(any())).thenReturn(mockDockerHub); // Mock out backend call to create service final String containerId = RandomStringUtils.randomAlphanumeric(5); @@ -333,8 +352,6 @@ public void testLaunchSwarmJobWithEnvSecret() throws Exception { Mockito.when(dockerClient.createServiceCmd(Mockito.any(ServiceSpec.class))).thenReturn(cmd); // Call method under test - PowerMockito.doCallRealMethod().when(dockerControlApi, "createDockerSwarmService", toCreate, dockerServer, DockerControlApi.NumReplicas.ZERO); - PowerMockito.doCallRealMethod().when(dockerControlApi).create(toCreate, user); dockerControlApi.create(toCreate, user); // Capture call to backend api mock @@ -376,13 +393,44 @@ public void testLaunchDockerContainerWithEnvSecret() throws Exception { .build(); // Class under test - final DockerControlApi dockerControlApi = PowerMockito.mock(DockerControlApi.class); + final DockerControlApi dockerControlApi = Mockito.spy(new DockerControlApi(dockerServerService, dockerHubService, kubernetesClientFactory)); // Mock out DockerControlApi#getDockerClient(dockerServer) final DockerClient dockerClient = Mockito.mock(DockerClient.class); - PowerMockito.doReturn(dockerClient).when(dockerControlApi, "getDockerClient", dockerServer); - PowerMockito.doReturn(dockerServer).when(dockerControlApi, "getServer"); +// PowerMockito.doReturn(dockerClient).when(dockerControlApi, "getDockerClient", dockerServer); + Mockito.doReturn(dockerClient).when(dockerControlApi) + .getDockerClient(any(DockerServerBase.DockerServer.class)); + +// PowerMockito.doReturn(dockerServer).when(dockerControlApi, "getServer"); + when(dockerServerService.getServer()).thenReturn(dockerServer); + + // Mock authConfig - return a valid DockerHub so authConfig doesn't need to access config + final org.nrg.containers.model.dockerhub.DockerHubBase.DockerHub mockDockerHub2 = Mockito.mock(org.nrg.containers.model.dockerhub.DockerHubBase.DockerHub.class); + when(mockDockerHub2.url()).thenReturn("docker.io"); + when(mockDockerHub2.username()).thenReturn(""); + when(mockDockerHub2.password()).thenReturn(""); + when(mockDockerHub2.token()).thenReturn(""); + when(mockDockerHub2.email()).thenReturn(""); + when(dockerHubService.getByUrl(any())).thenReturn(mockDockerHub2); + + // Mock listImagesCmd for getAllImages call + final com.github.dockerjava.api.command.ListImagesCmd listImagesCmd = Mockito.mock(com.github.dockerjava.api.command.ListImagesCmd.class); + when(dockerClient.listImagesCmd()).thenReturn(listImagesCmd); + when(listImagesCmd.exec()).thenReturn(java.util.Collections.emptyList()); + + // Mock pullImageCmd for pullImage call + final com.github.dockerjava.api.command.PullImageCmd pullImageCmd = Mockito.mock(com.github.dockerjava.api.command.PullImageCmd.class); + final com.github.dockerjava.api.command.PullImageResultCallback pullCallback = Mockito.mock(com.github.dockerjava.api.command.PullImageResultCallback.class); + when(dockerClient.pullImageCmd(any(String.class))).thenReturn(pullImageCmd); + when(pullImageCmd.start()).thenReturn(pullCallback); + when(pullCallback.awaitCompletion()).thenReturn(pullCallback); + + // Mock inspectImageCmd for getImageById call + final com.github.dockerjava.api.command.InspectImageCmd inspectImageCmd = Mockito.mock(com.github.dockerjava.api.command.InspectImageCmd.class); + final com.github.dockerjava.api.command.InspectImageResponse inspectImageResponse = Mockito.mock(com.github.dockerjava.api.command.InspectImageResponse.class); + when(dockerClient.inspectImageCmd(any(String.class))).thenReturn(inspectImageCmd); + when(inspectImageCmd.exec()).thenReturn(inspectImageResponse); // Mock out backend call to create service final String containerId = RandomStringUtils.randomAlphanumeric(5); @@ -398,8 +446,6 @@ public void testLaunchDockerContainerWithEnvSecret() throws Exception { Mockito.when(dockerClient.createContainerCmd(dockerImage)).thenReturn(cmd); // Call method under test - PowerMockito.doCallRealMethod().when(dockerControlApi, "createDockerContainer", toCreate, dockerServer); - PowerMockito.doCallRealMethod().when(dockerControlApi).create(toCreate, user); dockerControlApi.create(toCreate, user); // Capture call to backend api mock diff --git a/src/test/java/org/nrg/containers/services/CommandsAvailableTest.java b/src/test/java/org/nrg/containers/services/CommandsAvailableTest.java index cfa7f001..91a0bef4 100644 --- a/src/test/java/org/nrg/containers/services/CommandsAvailableTest.java +++ b/src/test/java/org/nrg/containers/services/CommandsAvailableTest.java @@ -1,14 +1,16 @@ package org.nrg.containers.services; import lombok.extern.slf4j.Slf4j; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; -import org.junit.runner.RunWith; -import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.nrg.containers.model.command.auto.Command; import org.nrg.containers.model.command.auto.CommandSummaryForContext; @@ -18,9 +20,6 @@ import org.nrg.xdat.security.helpers.Permissions; import org.nrg.xft.schema.Wrappers.GenericWrapper.GenericWrapperElement; import org.nrg.xft.security.UserI; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; import java.util.Collections; import java.util.List; @@ -29,19 +28,21 @@ import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mockStatic; import static org.nrg.containers.utils.ContainerServicePermissionUtils.PROJECT_EDIT_XML_PATH; import static org.nrg.containers.utils.ContainerServicePermissionUtils.PROJECT_READ_XML_PATH; import static org.nrg.xdat.security.SecurityManager.EDIT; import static org.nrg.xdat.security.SecurityManager.READ; -import static org.powermock.api.mockito.PowerMockito.mockStatic; @Slf4j -@RunWith(PowerMockRunner.class) -@PrepareForTest({Permissions.class, GenericWrapperElement.class}) public class CommandsAvailableTest { + private MockedStatic mockedGenericWrapperElement; + + private MockedStatic mockedPermissions; + @Rule public TestRule watcher = new TestWatcher() { protected void starting(Description description) { @@ -53,11 +54,11 @@ protected void finished(Description description) { } }; - @Mock private CommandEntityService commandEntityService; - @Mock private ContainerConfigService containerConfigService; + private CommandEntityService commandEntityService = Mockito.mock(CommandEntityService.class); + private ContainerConfigService containerConfigService = Mockito.mock(ContainerConfigService.class); - @Mock private UserI admin; - @Mock private UserI collaborator; + private UserI admin = Mockito.mock(UserI.class); + private UserI collaborator = Mockito.mock(UserI.class); private static final String project = "project"; private CommandService commandService; @@ -68,10 +69,17 @@ public void setup() { Mockito.when(admin.getUsername()).thenReturn("admin"); Mockito.when(collaborator.getLogin()).thenReturn("collab"); Mockito.when(collaborator.getUsername()).thenReturn("collab"); - + mockedGenericWrapperElement = mockStatic(GenericWrapperElement.class); + mockedPermissions = mockStatic(Permissions.class); commandService = new CommandServiceImpl(commandEntityService, containerConfigService); } + @After + public void tearDownStaticMocks() { + mockedPermissions.closeOnDemand(); + mockedGenericWrapperElement.closeOnDemand(); + } + @Test public void testNonProjectInput() throws Exception { // This UUID will stand in for the "context" and a data type @@ -117,29 +125,23 @@ public void testNonProjectInput() throws Exception { // Mock the call to get the enabled/disabled status Mockito.when(containerConfigService.isEnabled(eq(project), any(Long.class))).thenReturn(true); - - // Mock resolving xsi type - mockStatic(GenericWrapperElement.class); - PowerMockito.when(GenericWrapperElement.GetElement(any(String.class))) + mockedGenericWrapperElement.when(() -> GenericWrapperElement.GetElement(any(String.class))) .thenAnswer(invocation -> { GenericWrapperElement gwe = Mockito.mock(GenericWrapperElement.class); // Just return whatever xsi type was passed in - Mockito.when(gwe.getXSIType()).thenReturn(invocation.getArgumentAt(0, String.class)); + Mockito.when(gwe.getXSIType()).thenReturn(invocation.getArgument(0, String.class)); return gwe; }); - // Mock permissions checks - mockStatic(Permissions.class); - // Admin can read and edit - PowerMockito.when(Permissions.can(admin, PROJECT_READ_XML_PATH, project, READ)).thenReturn(true); - PowerMockito.when(Permissions.can(admin, xsiType + "/project", project, READ)).thenReturn(true); - PowerMockito.when(Permissions.can(admin, xsiType + "/project", project, EDIT)).thenReturn(true); + mockedPermissions.when(() -> Permissions.can(admin, PROJECT_READ_XML_PATH, project, READ)).thenReturn(true); + mockedPermissions.when(() -> Permissions.can(admin, xsiType + "/project", project, READ)).thenReturn(true); + mockedPermissions.when(() -> Permissions.can(admin, xsiType + "/project", project, EDIT)).thenReturn(true); // Collaborator can only read - PowerMockito.when(Permissions.can(collaborator, PROJECT_READ_XML_PATH, project, READ)).thenReturn(true); - PowerMockito.when(Permissions.can(collaborator, xsiType + "/project", project, READ)).thenReturn(true); - PowerMockito.when(Permissions.can(collaborator, xsiType + "/project", project, EDIT)).thenReturn(false); + mockedPermissions.when(() -> Permissions.can(collaborator, PROJECT_READ_XML_PATH, project, READ)).thenReturn(true); + mockedPermissions.when(() -> Permissions.can(collaborator, xsiType + "/project", project, READ)).thenReturn(true); + mockedPermissions.when(() -> Permissions.can(collaborator, xsiType + "/project", project, EDIT)).thenReturn(false); final CommandSummaryForContext readWrapperSummary = CommandSummaryForContext.create(command, wrapperRequiresRead, true, externalInputName); final CommandSummaryForContext editWrapperSummary = CommandSummaryForContext.create(command, wrapperRequiresEdit, true, externalInputName); @@ -199,27 +201,21 @@ public void testProjectInput() throws Exception { // Mock the call to get the enabled/disabled status Mockito.when(containerConfigService.isEnabled(eq(project), any(Long.class))).thenReturn(true); - - // Mock resolving xsi type - mockStatic(GenericWrapperElement.class); - PowerMockito.when(GenericWrapperElement.GetElement(any(String.class))) + mockedGenericWrapperElement.when(() -> GenericWrapperElement.GetElement(any(String.class))) .thenAnswer(invocation -> { GenericWrapperElement gwe = Mockito.mock(GenericWrapperElement.class); // Just return whatever xsi type was passed in - Mockito.when(gwe.getXSIType()).thenReturn(invocation.getArgumentAt(0, String.class)); + Mockito.when(gwe.getXSIType()).thenReturn(invocation.getArgument(0, String.class)); return gwe; }); - // Mock permissions checks - mockStatic(Permissions.class); - // Admin can read and edit - PowerMockito.when(Permissions.can(admin, PROJECT_READ_XML_PATH, project, READ)).thenReturn(true); - PowerMockito.when(Permissions.can(admin, PROJECT_EDIT_XML_PATH, project, EDIT)).thenReturn(true); + mockedPermissions.when(() -> Permissions.can(admin, PROJECT_READ_XML_PATH, project, READ)).thenReturn(true); + mockedPermissions.when(() -> Permissions.can(admin, PROJECT_EDIT_XML_PATH, project, EDIT)).thenReturn(true); // Collaborator can only read - PowerMockito.when(Permissions.can(collaborator, PROJECT_READ_XML_PATH, project, READ)).thenReturn(true); - PowerMockito.when(Permissions.can(collaborator, PROJECT_EDIT_XML_PATH, project, EDIT)).thenReturn(false); + mockedPermissions.when(() -> Permissions.can(collaborator, PROJECT_READ_XML_PATH, project, READ)).thenReturn(true); + mockedPermissions.when(() -> Permissions.can(collaborator, PROJECT_EDIT_XML_PATH, project, EDIT)).thenReturn(false); final CommandSummaryForContext readWrapperSummary = CommandSummaryForContext.create(command, wrapperRequiresRead, true, externalInputName); final CommandSummaryForContext editWrapperSummary = CommandSummaryForContext.create(command, wrapperRequiresEdit, true, externalInputName); diff --git a/src/test/java/org/nrg/containers/services/ContainerLogTest.java b/src/test/java/org/nrg/containers/services/ContainerLogTest.java index 29e2c4e7..92bcb0e5 100644 --- a/src/test/java/org/nrg/containers/services/ContainerLogTest.java +++ b/src/test/java/org/nrg/containers/services/ContainerLogTest.java @@ -20,6 +20,7 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.nrg.containers.api.ContainerControlApi; @@ -45,8 +46,8 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @Slf4j @@ -56,6 +57,8 @@ public class ContainerLogTest { @RunWith(JUnit4.class) public static class BaseTest { + @Rule public MockitoRule rule = MockitoJUnit.rule(); + @Rule public TestRule watcher = new TestWatcher() { protected void starting(Description description) { @@ -67,8 +70,6 @@ protected void finished(Description description) { } }; - @Rule public MockitoRule rule = MockitoJUnit.rule(); - @Rule public TemporaryFolder temp = new TemporaryFolder(new File(System.getProperty("java.io.tmpdir"))); @Mock public ContainerControlApi containerControlApi; diff --git a/src/test/java/org/nrg/containers/services/ContainerStatusUpdateTest.java b/src/test/java/org/nrg/containers/services/ContainerStatusUpdateTest.java index f564cf77..73c27240 100644 --- a/src/test/java/org/nrg/containers/services/ContainerStatusUpdateTest.java +++ b/src/test/java/org/nrg/containers/services/ContainerStatusUpdateTest.java @@ -6,7 +6,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.nrg.containers.daos.ContainerEntityRepository; import org.nrg.containers.model.container.auto.Container; import org.nrg.containers.model.container.entity.ContainerEntity; diff --git a/src/test/java/org/nrg/containers/utils/TestingUtils.java b/src/test/java/org/nrg/containers/utils/TestingUtils.java index 9dd1473c..69507b5c 100644 --- a/src/test/java/org/nrg/containers/utils/TestingUtils.java +++ b/src/test/java/org/nrg/containers/utils/TestingUtils.java @@ -21,6 +21,8 @@ import org.hamcrest.Matchers; import org.junit.rules.TemporaryFolder; import org.mockito.ArgumentMatcher; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.nrg.containers.api.KubernetesClient; import org.nrg.containers.api.KubernetesClientImpl; import org.nrg.containers.model.container.auto.Container; @@ -41,7 +43,6 @@ import org.nrg.xnat.services.archive.CatalogService; import org.nrg.xnat.turbine.utils.ArchivableItem; import org.nrg.xnat.utils.WorkflowUtils; -import org.powermock.api.mockito.PowerMockito; import org.springframework.test.context.transaction.TestTransaction; import java.io.File; @@ -63,10 +64,9 @@ import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; @Slf4j public class TestingUtils { @@ -354,19 +354,11 @@ public static void cleanSwarmServices(final DockerClient client, Collection> isMapWithEntry(final String key, final String value) { return new ArgumentMatcher>() { @Override - public boolean matches(final Object argument) { - if (argument == null || !Map.class.isAssignableFrom(argument.getClass())) { + public boolean matches(Map argument) { + if (argument == null) { return false; } - - final Map argumentMap = Maps.newHashMap(); - try { - argumentMap.putAll((Map)argument); - } catch (ClassCastException e) { - return false; - } - - for (final Map.Entry entry : argumentMap.entrySet()) { + for (final Map.Entry entry : argument.entrySet()) { if (entry.getKey().equals(key) && entry.getValue().equals(value)) { return true; } @@ -538,23 +530,31 @@ public static void setupMocksForSetupWrapupWorkflow(String uri, FakeWorkflow fak when(mockItem.getXSIType()).thenReturn(xsiType); when(mockItem.getProject()).thenReturn(project); final ExptURI mockUriObject = mock(ExptURI.class); - when(UriParserUtils.parseURI(uri)).thenReturn(mockUriObject); - when(mockUriObject.getSecurityItem()).thenReturn(mockItem); - fakeWorkflow.setId(uri); - ResourceData mockRD = mock(ResourceData.class); - when(mockRD.getItem()).thenReturn(mockItem); - when(mockCatalogService.getResourceDataFromUri(uri)).thenReturn(mockRD); - - FakeWorkflow setupWrapupWorkflow = new FakeWorkflow(); - setupWrapupWorkflow.setWfid(111); - setupWrapupWorkflow.setEventId(2); - PowerMockito.doReturn(setupWrapupWorkflow).when(PersistentWorkflowUtils.class, "getOrCreateWorkflowData", eq(2), - eq(mockUser), any(XFTItem.class), any(EventDetails.class)); - when(WorkflowUtils.buildOpenWorkflow(eq(mockUser), eq(xsiType), eq(id), eq(project), any(EventDetails.class))) - .thenReturn(setupWrapupWorkflow); - - when(WorkflowUtils.getUniqueWorkflow(mockUser, setupWrapupWorkflow.getWorkflowId().toString())) - .thenReturn(setupWrapupWorkflow); + try (MockedStatic mockUriParserUtils = mockStatic(UriParserUtils.class)) { + mockUriParserUtils.when(() -> UriParserUtils.parseURI(uri)).thenReturn(mockUriObject); + when(mockUriObject.getSecurityItem()).thenReturn(mockItem); + fakeWorkflow.setId(uri); + ResourceData mockRD = mock(ResourceData.class); + when(mockRD.getItem()).thenReturn(mockItem); + when(mockCatalogService.getResourceDataFromUri(uri)).thenReturn(mockRD); + + FakeWorkflow setupWrapupWorkflow = new FakeWorkflow(); + setupWrapupWorkflow.setWfid(111); + setupWrapupWorkflow.setEventId(2); + MockedStatic mockedStatic = mockStatic(PersistentWorkflowUtils.class); + // 使用 Mockito.doReturn().when() 来定义静态方法的行为 + mockedStatic.when(() -> PersistentWorkflowUtils.getOrCreateWorkflowData(eq(2), any(), any(), any(), any())) + .thenReturn(setupWrapupWorkflow); +// Mockito.doReturn(setupWrapupWorkflow).when(PersistentWorkflowUtils.class, "getOrCreateWorkflowData", eq(2), +// eq(mockUser), any(XFTItem.class), any(EventDetails.class)); + try (MockedStatic mockWorkflowUtils = mockStatic(WorkflowUtils.class)) { + mockWorkflowUtils.when(()->WorkflowUtils.buildOpenWorkflow(eq(mockUser), eq(xsiType), eq(id), eq(project), any(EventDetails.class))).thenReturn(setupWrapupWorkflow); + + try (MockedStatic mockWorkflowUtils1 = mockStatic(WorkflowUtils.class)) { + mockWorkflowUtils1.when(()->WorkflowUtils.getUniqueWorkflow(mockUser, setupWrapupWorkflow.getWorkflowId().toString())).thenReturn(setupWrapupWorkflow); + } + } + } } }