diff --git a/buildsupport/groovy/pom.xml b/buildsupport/groovy/pom.xml index 0417c0505a..541f5274e1 100644 --- a/buildsupport/groovy/pom.xml +++ b/buildsupport/groovy/pom.xml @@ -42,82 +42,88 @@ - - org.codehaus.groovy - groovy - ${groovy.version} - - - org.codehaus.groovy - groovy-ant - ${groovy.version} - - - org.codehaus.groovy - groovy-astbuilder - ${groovy.version} - - - org.codehaus.groovy - groovy-datetime - ${groovy.version} - - - org.codehaus.groovy - groovy-jmx - ${groovy.version} - - - org.codehaus.groovy - groovy-json - ${groovy.version} - - - org.codehaus.groovy - groovy-jsr223 - ${groovy.version} - - - org.codehaus.groovy - groovy-macro - ${groovy.version} - - - org.codehaus.groovy - groovy-nio - ${groovy.version} - - - org.codehaus.groovy - groovy-sql - ${groovy.version} - - - org.codehaus.groovy - groovy-templates - ${groovy.version} - - - org.codehaus.groovy - groovy-xml - ${groovy.version} - - - - org.codehaus.groovy - groovy-cli-commons - ${groovy.version} - - - org.codehaus.groovy - groovy-test - ${groovy.version} - - - org.codehaus.groovy - groovy-test-junit5 - ${groovy.version} - + + org.codehaus.groovy + groovy + ${groovy.version} + + + org.codehaus.groovy + groovy-ant + ${groovy.version} + + + org.codehaus.groovy + groovy-astbuilder + ${groovy.version} + + + org.codehaus.groovy + groovy-datetime + ${groovy.version} + + + org.codehaus.groovy + groovy-jmx + ${groovy.version} + + + org.codehaus.groovy + groovy-json + ${groovy.version} + + + org.codehaus.groovy + groovy-jsr223 + ${groovy.version} + + + org.codehaus.groovy + groovy-macro + ${groovy.version} + + + org.codehaus.groovy + groovy-nio + ${groovy.version} + + + org.codehaus.groovy + groovy-sql + ${groovy.version} + + + org.codehaus.groovy + groovy-templates + ${groovy.version} + + + org.codehaus.groovy + groovy-xml + ${groovy.version} + + + + org.codehaus.groovy + groovy-cli-commons + ${groovy.version} + + + org.codehaus.groovy + groovy-test + ${groovy.version} + + + org.codehaus.groovy + groovy-test-junit5 + ${groovy.version} + + + + org.codehaus.groovy + groovy-dateutil + ${groovy.version} + org.apache.ant diff --git a/buildsupport/testing/pom.xml b/buildsupport/testing/pom.xml index afa520dc6a..d551459e42 100644 --- a/buildsupport/testing/pom.xml +++ b/buildsupport/testing/pom.xml @@ -31,6 +31,8 @@ 4.13.5 1.19.1 1.168.0 + + 5.10.2 @@ -84,6 +86,12 @@ 4.13.2 + + org.junit.vintage + junit-vintage-engine + ${jupiter.version} + + org.assertj assertj-core diff --git a/components/nexus-base/src/main/java/org/sonatype/nexus/internal/security/upgrade/SecurityDatabaseUpgrade_1_4.java b/components/nexus-base/src/main/java/org/sonatype/nexus/internal/security/upgrade/SecurityDatabaseUpgrade_1_4.java new file mode 100644 index 0000000000..58e24365d1 --- /dev/null +++ b/components/nexus-base/src/main/java/org/sonatype/nexus/internal/security/upgrade/SecurityDatabaseUpgrade_1_4.java @@ -0,0 +1,61 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2008-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.internal.security.upgrade; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.sonatype.nexus.common.upgrade.Upgrades; +import org.sonatype.nexus.orient.DatabaseInstance; +import org.sonatype.nexus.orient.DatabaseInstanceNames; +import org.sonatype.nexus.orient.DatabaseUpgradeSupport; +import org.sonatype.nexus.orient.OClassNameBuilder; + +import com.orientechnologies.orient.core.sql.OCommandSQL; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Upgrade step to delete saml_users with empty id + * + */ +@Named +@Singleton +@Upgrades(model = DatabaseInstanceNames.SECURITY, from = "1.3", to = "1.4") +public class SecurityDatabaseUpgrade_1_4 // NOSONAR + extends DatabaseUpgradeSupport +{ + static final String DB_CLASS = new OClassNameBuilder().type("saml_user").build(); + + private static final String QUERY = String + .format("DELETE FROM %s WHERE id = ''", DB_CLASS); + + private final Provider securityDatabaseInstance; + + @Inject + public SecurityDatabaseUpgrade_1_4(@Named(DatabaseInstanceNames.SECURITY) final Provider securityDatabaseInstance) { + this.securityDatabaseInstance = checkNotNull(securityDatabaseInstance); + } + + @Override + public void apply() { + withDatabaseAndClass(securityDatabaseInstance, DB_CLASS, (db, type) -> { + int updates = db.command(new OCommandSQL(QUERY)).execute(); + if (updates > 0) { + log.debug("Deleted {} saml users with empty id.", updates); + } + }); + } +} diff --git a/components/nexus-common/pom.xml b/components/nexus-common/pom.xml index f11eae82ea..714cb7488e 100644 --- a/components/nexus-common/pom.xml +++ b/components/nexus-common/pom.xml @@ -157,6 +157,10 @@ org.codehaus.groovy groovy-cli-commons + + org.codehaus.groovy + groovy-dateutil + commons-cli diff --git a/components/nexus-common/src/main/java/org/sonatype/nexus/common/analytics/ContentUsage.java b/components/nexus-common/src/main/java/org/sonatype/nexus/common/analytics/AggregatedEventMetric.java similarity index 74% rename from components/nexus-common/src/main/java/org/sonatype/nexus/common/analytics/ContentUsage.java rename to components/nexus-common/src/main/java/org/sonatype/nexus/common/analytics/AggregatedEventMetric.java index 9aa0a80201..7e33cb8e2f 100644 --- a/components/nexus-common/src/main/java/org/sonatype/nexus/common/analytics/ContentUsage.java +++ b/components/nexus-common/src/main/java/org/sonatype/nexus/common/analytics/AggregatedEventMetric.java @@ -12,19 +12,9 @@ */ package org.sonatype.nexus.common.analytics; -import java.util.Map; - -public interface ContentUsage +public interface AggregatedEventMetric { - Map getMetrics(); - - boolean shouldBlock(); - - void recalculate(); - - void recalculate(boolean blockingStateEventCounterEnable); - - int getBlockingStateEventCounter(); + int get(); - void clearBlockingStateEventCounter(); + void reset(); } diff --git a/components/nexus-common/src/main/java/org/sonatype/nexus/common/analytics/RequestsMetric.java b/components/nexus-common/src/main/java/org/sonatype/nexus/common/analytics/RequestsMetric.java new file mode 100644 index 0000000000..8ea074ed59 --- /dev/null +++ b/components/nexus-common/src/main/java/org/sonatype/nexus/common/analytics/RequestsMetric.java @@ -0,0 +1,20 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2008-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.common.analytics; + +public interface RequestsMetric +{ + long get(); + + void reset(); +} diff --git a/components/nexus-common/src/main/java/org/sonatype/nexus/common/app/FeatureFlags.java b/components/nexus-common/src/main/java/org/sonatype/nexus/common/app/FeatureFlags.java index 9aec2b9888..92b7ea33b7 100644 --- a/components/nexus-common/src/main/java/org/sonatype/nexus/common/app/FeatureFlags.java +++ b/components/nexus-common/src/main/java/org/sonatype/nexus/common/app/FeatureFlags.java @@ -144,5 +144,4 @@ public interface FeatureFlags String REACT_ROLES_MODAL_NAMED = "${nexus.react.roles.modal.enabled:-true}"; String BLOBSTORE_OWNERSHIP_CHECK_DISABLED_NAMED = "${nexus.blobstore.s3.ownership.check.disabled:-false}"; - } diff --git a/components/nexus-core/src/test/java/org/sonatype/nexus/internal/capability/CapabilityStorageExportTest.java b/components/nexus-core/src/test/java/org/sonatype/nexus/internal/capability/CapabilityStorageExportTest.java index 88231ae89c..2cd578cab1 100644 --- a/components/nexus-core/src/test/java/org/sonatype/nexus/internal/capability/CapabilityStorageExportTest.java +++ b/components/nexus-core/src/test/java/org/sonatype/nexus/internal/capability/CapabilityStorageExportTest.java @@ -32,7 +32,6 @@ import org.junit.Test; import static java.util.stream.Collectors.toList; -import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.not; @@ -83,7 +82,8 @@ public void testExportImportToJson() throws Exception { containsInAnyOrder("notes 1", "notes 2")); List> attributes = importedItems.stream().map(CapabilityStorageItem::getProperties).collect(toList()); - assertThat(attributes.toString(), allOf(containsString("Capability"), containsString("Testing"))); + assertThat(attributes.toString(), containsString("Capability")); + assertThat(attributes.toString(), containsString("Testing")); // make sure sensitive data is not serialized assertThat(attributes.toString(), not(containsString("admin123"))); } diff --git a/components/nexus-core/src/test/java/org/sonatype/nexus/internal/provisioning/CoreApiImplTest.groovy b/components/nexus-core/src/test/java/org/sonatype/nexus/internal/provisioning/CoreApiImplTest.groovy index d4fc94c454..4fbbd61c3a 100644 --- a/components/nexus-core/src/test/java/org/sonatype/nexus/internal/provisioning/CoreApiImplTest.groovy +++ b/components/nexus-core/src/test/java/org/sonatype/nexus/internal/provisioning/CoreApiImplTest.groovy @@ -29,7 +29,6 @@ import org.sonatype.nexus.internal.app.BaseUrlCapabilityDescriptor import org.sonatype.nexus.internal.capability.DefaultCapabilityReference import org.sonatype.nexus.internal.httpclient.TestHttpClientConfiguration -import org.junit.Test import spock.lang.Specification /** @@ -56,8 +55,7 @@ class CoreApiImplTest private static final ProxyConfiguration EXISTING_HTTP = new ProxyConfiguration( http: new ProxyServerConfiguration(enabled: true, host: 'http', port: 1)) - @Test - public void 'Can set base url without an existing capability'() { + def 'Can set base url without an existing capability'() { given: List existingCapabilities = [reference] @@ -70,11 +68,9 @@ class CoreApiImplTest 1 * context.descriptor() >> descriptor 1 * descriptor.type() >> new CapabilityType('not baseurl') 1 * capabilityRegistry.add(BaseUrlCapabilityDescriptor.TYPE, true, _, [url: 'foo']) - } - @Test - public void 'Can set base url with an existing capability'() { + def 'Can set base url with an existing capability'() { given: List existingCapabilities = [reference] @@ -91,9 +87,8 @@ class CoreApiImplTest 1 * reference.notes() >> 'whatever' 1 * capabilityRegistry.update(identity, true, 'whatever', [url: 'bar']) } - - @Test - public void 'Can delete an existing base url capability'() { + + def 'Can delete an existing base url capability'() { given: List existingCapabilities = [reference] @@ -109,8 +104,7 @@ class CoreApiImplTest 1 * capabilityRegistry.remove(identity) } - @Test - public void 'Can delete when base url capability is not configured'() { + def 'Can delete when base url capability is not configured'() { given: List existingCapabilities = [] @@ -122,8 +116,7 @@ class CoreApiImplTest 0 * capabilityRegistry.remove(identity) } - @Test - public void 'Can set http proxy settings without auth'() { + def 'Can set http proxy settings without auth'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration() @@ -143,8 +136,7 @@ class CoreApiImplTest } } - @Test - public void 'Can set http proxy settings with basic auth'() { + def 'Can set http proxy settings with basic auth'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration() @@ -167,8 +159,7 @@ class CoreApiImplTest } } - @Test - public void 'Can set http proxy settings with NTLM auth'() { + def 'Can set http proxy settings with NTLM auth'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration() @@ -193,8 +184,7 @@ class CoreApiImplTest } } - @Test - public void 'Can remove http proxy configuration'() { + def 'Can remove http proxy configuration'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration(proxy: EXISTING_HTTP) @@ -207,8 +197,7 @@ class CoreApiImplTest !configuration.proxy } - @Test - public void 'Cannot set https proxy without http proxy'() { + def 'Cannot set https proxy without http proxy'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration() @@ -222,8 +211,7 @@ class CoreApiImplTest 0 * httpClientManager.setConfiguration(_) } - @Test - public void 'Can set https proxy settings without auth'() { + def 'Can set https proxy settings without auth'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration(proxy: EXISTING_HTTP) @@ -243,8 +231,7 @@ class CoreApiImplTest } } - @Test - public void 'Can set https proxy settings with basic auth'() { + def 'Can set https proxy settings with basic auth'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration(proxy: EXISTING_HTTP) @@ -267,8 +254,7 @@ class CoreApiImplTest } } - @Test - public void 'Can set https proxy settings with NTLM auth'() { + def 'Can set https proxy settings with NTLM auth'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration(proxy: EXISTING_HTTP) @@ -293,8 +279,7 @@ class CoreApiImplTest } } - @Test - public void 'Can remove https proxy configuration'() { + def 'Can remove https proxy configuration'() { given: ProxyConfiguration proxies = EXISTING_HTTP.copy() proxies.https = new ProxyServerConfiguration(enabled: true, host:'https', port: 2) @@ -311,8 +296,7 @@ class CoreApiImplTest !configuration.proxy.https } - @Test - public void 'Can configure connection timeout'() { + def 'Can configure connection timeout'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration() @@ -325,8 +309,7 @@ class CoreApiImplTest configuration.connection.timeout == Time.seconds(5) } - @Test - public void 'Configure connection timeout fails when values are out of bounds'() { + def 'Configure connection timeout fails when values are out of bounds'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration() @@ -342,8 +325,7 @@ class CoreApiImplTest value << [-1, 3601] } - @Test - public void 'Can configure connection retries'() { + def 'Can configure connection retries'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration() @@ -356,8 +338,7 @@ class CoreApiImplTest configuration.connection.retries == 5 } - @Test - public void 'Configure connection retries fails when values are out of bounds'() { + def 'Configure connection retries fails when values are out of bounds'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration() @@ -373,8 +354,7 @@ class CoreApiImplTest value << [-1, 11] } - @Test - public void 'Can customize user agent'() { + def 'Can customize user agent'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration() @@ -387,8 +367,7 @@ class CoreApiImplTest configuration.connection.userAgentSuffix == 'foo' } - @Test - public void 'Can set and unset non-proxy hosts'() { + def 'Can set and unset non-proxy hosts'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration(proxy: EXISTING_HTTP) @@ -409,8 +388,7 @@ class CoreApiImplTest !configuration.proxy.nonProxyHosts } - @Test - public void 'Cannot non-proxy hosts without a proxy configured'() { + def 'Cannot non-proxy hosts without a proxy configured'() { given: HttpClientConfiguration configuration = new TestHttpClientConfiguration() diff --git a/components/nexus-core/src/test/java/org/sonatype/nexus/internal/selector/SelectorConfigurationExportTest.java b/components/nexus-core/src/test/java/org/sonatype/nexus/internal/selector/SelectorConfigurationExportTest.java index 4ec702c008..45363384d4 100644 --- a/components/nexus-core/src/test/java/org/sonatype/nexus/internal/selector/SelectorConfigurationExportTest.java +++ b/components/nexus-core/src/test/java/org/sonatype/nexus/internal/selector/SelectorConfigurationExportTest.java @@ -28,7 +28,6 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.anyOf; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -53,9 +52,9 @@ public void tearDown() { @Test public void testExportImportToJson() throws Exception { - List selectorConfigurations = Arrays.asList( - createSelectorConfiguration("config_1"), - createSelectorConfiguration("config_2")); + SelectorConfiguration config1 = createSelectorConfiguration("config_1"); + SelectorConfiguration config2 = createSelectorConfiguration("config_2"); + List selectorConfigurations = Arrays.asList(config1, config2); SelectorConfigurationStore store = mock(SelectorConfigurationStore.class); when(store.browse()).thenReturn(selectorConfigurations); @@ -66,9 +65,10 @@ public void testExportImportToJson() throws Exception { jsonExporter.importFromJson(jsonFile, SelectorConfigurationData.class); assertThat(importedData.size(), is(2)); - importedData.forEach(data -> assertThat(data, anyOf( - is(selectorConfigurations.get(0)), - is(selectorConfigurations.get(1))))); + SelectorConfigurationData importedData1 = importedData.get(0); + SelectorConfigurationData importedData2 = importedData.get(0); + assertThat(importedData1.equals(config1) || importedData1.equals(config2), is(true)); + assertThat(importedData2.equals(config1) || importedData2.equals(config2), is(true)); } private SelectorConfiguration createSelectorConfiguration(final String name) { diff --git a/components/nexus-repository-content/src/main/java/org/sonatype/nexus/repository/content/store/internal/RepositoryNameIdMappingCache.java b/components/nexus-repository-content/src/main/java/org/sonatype/nexus/repository/content/store/RepositoryNameIdMappingCache.java similarity index 89% rename from components/nexus-repository-content/src/main/java/org/sonatype/nexus/repository/content/store/internal/RepositoryNameIdMappingCache.java rename to components/nexus-repository-content/src/main/java/org/sonatype/nexus/repository/content/store/RepositoryNameIdMappingCache.java index 2c39bb4378..324d6a2944 100644 --- a/components/nexus-repository-content/src/main/java/org/sonatype/nexus/repository/content/store/internal/RepositoryNameIdMappingCache.java +++ b/components/nexus-repository-content/src/main/java/org/sonatype/nexus/repository/content/store/RepositoryNameIdMappingCache.java @@ -10,8 +10,9 @@ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the * Eclipse Foundation. All other trademarks are the property of their respective owners. */ -package org.sonatype.nexus.repository.content.store.internal; +package org.sonatype.nexus.repository.content.store; +import java.util.AbstractMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -27,8 +28,6 @@ import org.sonatype.nexus.common.event.EventAware; import org.sonatype.nexus.repository.Format; import org.sonatype.nexus.repository.Repository; -import org.sonatype.nexus.repository.content.store.ContentRepositoryStore; -import org.sonatype.nexus.repository.content.store.FormatStoreManager; import org.sonatype.nexus.repository.manager.RepositoryCreatedEvent; import org.sonatype.nexus.repository.manager.RepositoryDeletedEvent; @@ -78,12 +77,11 @@ public void on(final RepositoryDeletedEvent event) { } } - public List getRepositoryIds(List repositoryNames, String format) { + public Map getRepositoryNameIds(List repositoryNames, String format) { return repositoryNames.stream() - .map(repositoryName -> fetchRepositoryId(repositoryName, format)) - .filter(OptionalInt::isPresent) - .map(OptionalInt::getAsInt) - .collect(Collectors.toList()); + .map(name -> new AbstractMap.SimpleEntry<>(fetchRepositoryId(name, format), name)) + .filter(entry -> entry.getKey().isPresent()) + .collect(Collectors.toMap(entry -> entry.getKey().getAsInt(), AbstractMap.SimpleEntry::getValue)); } private Map getCache() { diff --git a/components/nexus-repository-content/src/test/java/org/sonatype/nexus/repository/content/store/internal/RepositoryNameIdMappingCacheTest.java b/components/nexus-repository-content/src/test/java/org/sonatype/nexus/repository/content/store/RepositoryNameIdMappingCacheTest.java similarity index 82% rename from components/nexus-repository-content/src/test/java/org/sonatype/nexus/repository/content/store/internal/RepositoryNameIdMappingCacheTest.java rename to components/nexus-repository-content/src/test/java/org/sonatype/nexus/repository/content/store/RepositoryNameIdMappingCacheTest.java index d12b6a8aa4..eba3f1c081 100644 --- a/components/nexus-repository-content/src/test/java/org/sonatype/nexus/repository/content/store/internal/RepositoryNameIdMappingCacheTest.java +++ b/components/nexus-repository-content/src/test/java/org/sonatype/nexus/repository/content/store/RepositoryNameIdMappingCacheTest.java @@ -10,7 +10,7 @@ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the * Eclipse Foundation. All other trademarks are the property of their respective owners. */ -package org.sonatype.nexus.repository.content.store.internal; +package org.sonatype.nexus.repository.content.store; import java.util.Arrays; import java.util.HashMap; @@ -21,8 +21,6 @@ import org.sonatype.goodies.testsupport.TestSupport; import org.sonatype.nexus.repository.Format; import org.sonatype.nexus.repository.Repository; -import org.sonatype.nexus.repository.content.store.ContentRepositoryStore; -import org.sonatype.nexus.repository.content.store.FormatStoreManager; import org.sonatype.nexus.repository.manager.RepositoryCreatedEvent; import org.sonatype.nexus.repository.manager.RepositoryDeletedEvent; @@ -35,6 +33,7 @@ import org.mockito.Mock; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.hasEntry; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -61,8 +60,10 @@ public void setup() { @Test public void testGetRepositoryIds() { - List repositoryIds = initializeCache(); - assertThat(repositoryIds, contains(1, 2)); + Map repositoryIds = initializeCache(); + assertThat(repositoryIds.keySet(), contains(1, 2)); + assertThat(repositoryIds, hasEntry(1, "repo1")); + assertThat(repositoryIds, hasEntry(2, "repo2")); } @Test @@ -74,8 +75,8 @@ public void testShouldAddNewRepositoryIdOnRepositoryCreatedEvent() { underTest.on(new RepositoryCreatedEvent(repository("repo3"))); - List repositoryIds = underTest.getRepositoryIds(Arrays.asList("repo3"), "raw"); - assertThat(repositoryIds, contains(3)); + Map repositoryIds = underTest.getRepositoryNameIds(Arrays.asList("repo3"), "raw"); + assertThat(repositoryIds, hasEntry(3, "repo3")); } @Test @@ -84,11 +85,11 @@ public void testShouldRemoveRepositoryIdOnRepositoryDeletedEvent() { underTest.on(new RepositoryDeletedEvent(repository("repo1"))); - List repositoryIds = underTest.getRepositoryIds(Arrays.asList("repo1"), "raw"); - assertThat(repositoryIds, not(hasItem(1))); + Map repositoryIds = underTest.getRepositoryNameIds(Arrays.asList("repo1"), "raw"); + assertThat(repositoryIds, not(hasEntry(2, "repo2"))); } - private List initializeCache() { + private Map initializeCache() { List repositoryNames = Arrays.asList("repo1", "repo2"); Map nameIdOne = getRepositoryNameId("repo1", 1); Map nameIdTwo = getRepositoryNameId("repo2", 2); @@ -96,7 +97,7 @@ private List initializeCache() { when(contentRepositoryStore.readAllContentRepositoryIds(any())).thenReturn(repositoryNameIds); - return underTest.getRepositoryIds(repositoryNames, "raw"); + return underTest.getRepositoryNameIds(repositoryNames, "raw"); } private Map getRepositoryNameId(String name, int id) { diff --git a/components/nexus-repository-services/pom.xml b/components/nexus-repository-services/pom.xml index 8f09a436b9..e48e690837 100644 --- a/components/nexus-repository-services/pom.xml +++ b/components/nexus-repository-services/pom.xml @@ -27,6 +27,10 @@ ${project.groupId}:${project.artifactId} bundle + + 5.10.2 + + org.sonatype.nexus @@ -234,6 +238,13 @@ JUnitParams test + + + org.junit.vintage + junit-vintage-engine + ${junit-vintage-engine.version} + test + diff --git a/components/nexus-repository-services/src/main/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupport.java b/components/nexus-repository-services/src/main/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupport.java index ec3901fa88..d21e48282a 100644 --- a/components/nexus-repository-services/src/main/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupport.java +++ b/components/nexus-repository-services/src/main/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupport.java @@ -85,6 +85,9 @@ public abstract class ProxyFacetSupport public static final String BYPASS_HTTP_ERRORS_HEADER_VALUE = "true"; + private static final String PROXY_REMOTE_FETCH_SKIP_MARKER = + "proxy.remote-fetch.skip"; + @VisibleForTesting static final String CONFIG_KEY = "proxy"; @@ -275,9 +278,19 @@ public Content get(final Context context) throws IOException { getEventManager().post(new ProxyCacheHitEvent(format, isReplication)); return content; } + boolean remoteFetchSkipMarker = isRemoteFetchSkipMarkerEnabled(context); + if (remoteFetchSkipMarker) { + return content; + } return get(context, content); } + private boolean isRemoteFetchSkipMarkerEnabled(final Context context) { + Object marker = context.getAttributes() + .get(PROXY_REMOTE_FETCH_SKIP_MARKER); + return TRUE.equals(marker); + } + /** * Attempt to retrieve from the remote using proxy co-operation */ diff --git a/components/nexus-repository-services/src/test/java/org/sonatype/nexus/repository/proxy/ConcurrentProxyTest.java b/components/nexus-repository-services/src/test/java/org/sonatype/nexus/repository/proxy/ConcurrentProxyTest.java index fbcef5a693..b25070c672 100644 --- a/components/nexus-repository-services/src/test/java/org/sonatype/nexus/repository/proxy/ConcurrentProxyTest.java +++ b/components/nexus-repository-services/src/test/java/org/sonatype/nexus/repository/proxy/ConcurrentProxyTest.java @@ -195,6 +195,7 @@ public void setUp() throws Exception { // this is the mock index used for indirect requests when(metaRequest.getPath()).thenReturn("index.json"); when(metaContext.getRequest()).thenReturn(metaRequest); + when(metaContext.getAttributes()).thenReturn(new AttributesMap()); when(attributesMap.get(CacheInfo.class)).thenReturn(cacheInfo); diff --git a/components/nexus-repository-services/src/test/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupportTest.java b/components/nexus-repository-services/src/test/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupportTest.java index 54d214e6de..02983d796a 100644 --- a/components/nexus-repository-services/src/test/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupportTest.java +++ b/components/nexus-repository-services/src/test/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupportTest.java @@ -57,6 +57,7 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; @@ -65,7 +66,9 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.sonatype.nexus.repository.proxy.ProxyFacetSupport.BYPASS_HTTP_ERRORS_HEADER_NAME; import static org.sonatype.nexus.repository.proxy.ProxyFacetSupport.BYPASS_HTTP_ERRORS_HEADER_VALUE; @@ -125,9 +128,15 @@ protected String getUrl(@Nonnull final Context context) { @Mock Context cachedContext; + @Mock + AttributesMap cachedContextAttributesMap; + @Mock Context missingContext; + @Mock + AttributesMap missingContextAttributesMap; + @Mock CacheControllerHolder cacheControllerHolder; @@ -163,6 +172,11 @@ public void setUp() throws Exception { when(format.getValue()).thenReturn("raw"); when(repository.getFormat()).thenReturn(format); + when(cachedContextAttributesMap.get("proxy.remote-fetch.skip")).thenReturn(false); + when(missingContextAttributesMap.get("proxy.remote-fetch.skip")).thenReturn(false); + when(cachedContext.getAttributes()).thenReturn(cachedContextAttributesMap); + when(missingContext.getAttributes()).thenReturn(missingContextAttributesMap); + underTest.installDependencies(eventManager); underTest.attach(repository); underTest.configureCooperation(new DefaultCooperation2Factory(), false, Duration.ofSeconds(0), @@ -170,6 +184,46 @@ public void setUp() throws Exception { underTest.buildCooperation(); } + @Test + public void testGetRemoteFetchSkipNoContentHasFound() throws Exception { + doReturn(null).when(underTest).getCachedContent(cachedContext); + when(cachedContextAttributesMap.get("proxy.remote-fetch.skip")) + .thenReturn(true); + + Content actual = underTest.get(cachedContext); + assertNull(actual); + verify(underTest, never()).fetch(any(), any(), any()); + verify(underTest, never()).store(any(), any()); + } + + @Test + public void testGetRemoteFetchSkipContentHasFound() throws Exception { + when(cachedContextAttributesMap.get("proxy.remote-fetch.skip")) + .thenReturn(true); + doReturn(content).when(underTest).getCachedContent(cachedContext); + + when(cacheController.isStale(cacheInfo)).thenReturn(false); + + Content actual = underTest.get(cachedContext); + assertThat(actual, is(content)); + verify(underTest, never()).fetch(any(), any(), any()); + verify(underTest, never()).store(any(), any()); + } + + @Test + public void testGetRemoteFetchSkipContentHasFoundWithInvalidCache() throws Exception { + when(cachedContextAttributesMap.get("proxy.remote-fetch.skip")) + .thenReturn(true); + doReturn(content).when(underTest).getCachedContent(cachedContext); + + when(cacheController.isStale(cacheInfo)).thenReturn(true); + + Content actual = underTest.get(cachedContext); + assertThat(actual, is(content)); + verify(underTest, never()).fetch(any(), any(), any()); + verify(underTest, never()).store(any(), any()); + } + @Test public void testGet() throws IOException { when(cacheController.isStale(cacheInfo)).thenReturn(false); diff --git a/components/nexus-repository-view/src/main/java/org/sonatype/nexus/repository/http/HttpStatus.java b/components/nexus-repository-view/src/main/java/org/sonatype/nexus/repository/http/HttpStatus.java index a5a006823a..45eb0e0912 100644 --- a/components/nexus-repository-view/src/main/java/org/sonatype/nexus/repository/http/HttpStatus.java +++ b/components/nexus-repository-view/src/main/java/org/sonatype/nexus/repository/http/HttpStatus.java @@ -98,6 +98,8 @@ private HttpStatus() { */ public static final int UNPROCESSABLE_ENTITY = 422; + public static final int TOO_MANY_REQUESTS = 429; + public static final int INTERNAL_SERVER_ERROR = 500; public static final int NOT_IMPLEMENTED = 501; diff --git a/components/nexus-security/src/test/java/org/sonatype/nexus/security/PasswordHelperTest.java b/components/nexus-security/src/test/java/org/sonatype/nexus/security/PasswordHelperTest.java index 2e56e9de13..52d4514adf 100644 --- a/components/nexus-security/src/test/java/org/sonatype/nexus/security/PasswordHelperTest.java +++ b/components/nexus-security/src/test/java/org/sonatype/nexus/security/PasswordHelperTest.java @@ -26,7 +26,6 @@ import org.junit.Test; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; @@ -73,14 +72,18 @@ public void testEncrypt_NullInput() throws Exception { @Test public void testEncrypt_EmptyInput() throws Exception { - assertEncrypt(legacyPasswordHelper, "", allOf(startsWith("{"), endsWith("}"))); - assertEncrypt(customPasswordHelper, "", allOf(startsWith("~{"), endsWith("}~"))); + assertEncrypt(legacyPasswordHelper, "", is(startsWith("{"))); + assertEncrypt(legacyPasswordHelper, "", is(endsWith("}"))); + assertEncrypt(customPasswordHelper, "", is(startsWith("~{"))); + assertEncrypt(customPasswordHelper, "", is(endsWith("}~"))); } @Test public void testEncrypt_PlainInput() throws Exception { - assertEncrypt(legacyPasswordHelper, "test", allOf(startsWith("{"), endsWith("}"))); - assertEncrypt(customPasswordHelper, "test", allOf(startsWith("~{"), endsWith("}~"))); + assertEncrypt(legacyPasswordHelper, "test", is(startsWith("{"))); + assertEncrypt(legacyPasswordHelper, "test", is(endsWith("}"))); + assertEncrypt(customPasswordHelper, "test", is(startsWith("~{"))); + assertEncrypt(customPasswordHelper, "test", is(endsWith("}~"))); } @Test @@ -94,8 +97,13 @@ public void testEncrypt_AlreadyEncryptedInput() throws Exception { @Test public void testEncrypt_StringIncludingShields() throws Exception { //check the resultant value is protected by braces and has been encrypted (not equal to the input string) - assertEncrypt(legacyPasswordHelper, "{test}", allOf(startsWith("{"), endsWith("}"), not("{test}"))); - assertEncrypt(customPasswordHelper, "{test}", allOf(startsWith("~{"), endsWith("}~"), not("~{test}~"))); + assertEncrypt(legacyPasswordHelper, "{test}", is(startsWith("{"))); + assertEncrypt(legacyPasswordHelper, "{test}", is(endsWith("}"))); + assertEncrypt(legacyPasswordHelper, "{test}", is(not("{test}"))); + + assertEncrypt(customPasswordHelper, "{test}", is(startsWith("~{"))); + assertEncrypt(customPasswordHelper, "{test}", is(endsWith("}~"))); + assertEncrypt(customPasswordHelper, "{test}", is(not("~{test}~"))); } @Test diff --git a/components/nexus-testsupport/pom.xml b/components/nexus-testsupport/pom.xml index dd4f721da1..72548636e0 100644 --- a/components/nexus-testsupport/pom.xml +++ b/components/nexus-testsupport/pom.xml @@ -36,6 +36,11 @@ org.sonatype.goodies goodies-testsupport + + + org.junit.vintage + junit-vintage-engine + diff --git a/components/nexus-ui-plugin/src/frontend/src/components/widgets/Textarea/Textarea.jsx b/components/nexus-ui-plugin/src/frontend/src/components/widgets/Textarea/Textarea.jsx deleted file mode 100644 index d0d153a108..0000000000 --- a/components/nexus-ui-plugin/src/frontend/src/components/widgets/Textarea/Textarea.jsx +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Sonatype Nexus (TM) Open Source Version - * Copyright (c) 2008-present Sonatype, Inc. - * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. - * - * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, - * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. - * - * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks - * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the - * Eclipse Foundation. All other trademarks are the property of their respective owners. - */ -import React, {forwardRef} from 'react'; -import PropTypes from 'prop-types'; -import {NxTextInput} from "@sonatype/react-shared-components"; - -/** - * @since 3.22 - * @deprecated prefer NxTextInput instead - */ -const Textarea = forwardRef(({name, id, onChange, ...attrs}, ref) => { - const handleChange = (value) => { - if (onChange) { - onChange({ - target: { - id: id || name, - name: name, - type: "textarea", - value - } - }); - } - }; - return ; -}); - -Textarea.propTypes = { - validationErrors: PropTypes.oneOfType([PropTypes.string, PropTypes.array]) -}; - -export default Textarea; diff --git a/components/nexus-ui-plugin/src/frontend/src/index.js b/components/nexus-ui-plugin/src/frontend/src/index.js index 6941fa7565..cfd25b6065 100644 --- a/components/nexus-ui-plugin/src/frontend/src/index.js +++ b/components/nexus-ui-plugin/src/frontend/src/index.js @@ -37,9 +37,6 @@ export { default as ContentBody } from './components/layout/common/ContentBody/C export { default as Section } from './components/layout/common/Section/Section'; export { default as SectionFooter } from './components/layout/common/SectionFooter/SectionFooter'; export { default as SectionToolbar } from './components/layout/common/SectionToolbar/SectionToolbar'; -export { default as MasterDetail } from './components/layout/common/MasterDetail/MasterDetail'; -export { default as Master } from './components/layout/common/MasterDetail/Master'; -export { default as Detail } from './components/layout/common/MasterDetail/Detail'; export { default as Page } from './components/layout/common/Page/Page'; export { default as PageActions } from './components/layout/common/PageActions/PageActions'; export { default as PageHeader } from './components/layout/common/PageHeader/PageHeader'; @@ -57,13 +54,10 @@ export { default as ReadOnlyField } from './components/widgets/ReadOnlyField/Rea export { default as SslCertificateDetailsModal } from './components/widgets/SslCertificateDetailsModal/SslCertificateDetailsModal'; -export {default as Textarea} from './components/widgets/Textarea/Textarea'; export {default as Textfield} from './components/widgets/Textfield/Textfield'; export { default as UseNexusTruststore } from './components/widgets/UseTruststoreCheckbox/UseNexusTruststore'; -export { default as TokenMachine } from './components/machines/TokenMachine'; - export * from './interface/urlUtil'; export * from './interface/versionUtil'; diff --git a/components/nexus-ui-plugin/src/frontend/src/interface/TestUtils.js b/components/nexus-ui-plugin/src/frontend/src/interface/TestUtils.js index 8a3084b17e..fd4d000e68 100644 --- a/components/nexus-ui-plugin/src/frontend/src/interface/TestUtils.js +++ b/components/nexus-ui-plugin/src/frontend/src/interface/TestUtils.js @@ -90,7 +90,7 @@ export default class TestUtils { querySubmitButton: () => screen.queryByRole('button', {name: SAVE_BUTTON_LABEL}), queryDiscardButton: () => screen.queryByRole('button', {name: DISCARD_BUTTON_LABEL}), queryFormError: (message) => { - const options = {selector: '.nx-form__validation-errors .nx-alert__content'}; + const options = {selector: '.nx-form--show-validation-errors.nx-form--has-validation-errors .nx-form__validation-errors .nx-alert__content'}; if (message) { return screen.queryByText(`${TestUtils.THERE_WERE_ERRORS} ${message}`, options); } diff --git a/components/nexus-ui-plugin/src/frontend/src/components/layout/common/MasterDetail/Detail.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/layout/MasterDetail/Detail.jsx similarity index 100% rename from components/nexus-ui-plugin/src/frontend/src/components/layout/common/MasterDetail/Detail.jsx rename to plugins/nexus-coreui-plugin/src/frontend/src/components/layout/MasterDetail/Detail.jsx diff --git a/components/nexus-ui-plugin/src/frontend/src/components/layout/common/MasterDetail/Master.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/layout/MasterDetail/Master.jsx similarity index 100% rename from components/nexus-ui-plugin/src/frontend/src/components/layout/common/MasterDetail/Master.jsx rename to plugins/nexus-coreui-plugin/src/frontend/src/components/layout/MasterDetail/Master.jsx diff --git a/components/nexus-ui-plugin/src/frontend/src/components/layout/common/MasterDetail/MasterDetail.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/layout/MasterDetail/MasterDetail.jsx similarity index 97% rename from components/nexus-ui-plugin/src/frontend/src/components/layout/common/MasterDetail/MasterDetail.jsx rename to plugins/nexus-coreui-plugin/src/frontend/src/components/layout/MasterDetail/MasterDetail.jsx index 72060bc5d5..d80dbe9393 100644 --- a/components/nexus-ui-plugin/src/frontend/src/components/layout/common/MasterDetail/MasterDetail.jsx +++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/layout/MasterDetail/MasterDetail.jsx @@ -14,11 +14,11 @@ import classNames from 'classnames'; import React, {Children, cloneElement, useState} from 'react'; import PropTypes from 'prop-types'; +import {ExtJS} from '@sonatype/nexus-ui-plugin'; + import Master from './Master'; import Detail from './Detail'; -import ExtJS from '../../../../interface/ExtJS'; - /** * @since 3.24 */ diff --git a/components/nexus-ui-plugin/src/frontend/src/components/layout/common/MasterDetail/MasterDetail.test.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/layout/MasterDetail/MasterDetail.test.jsx similarity index 95% rename from components/nexus-ui-plugin/src/frontend/src/components/layout/common/MasterDetail/MasterDetail.test.jsx rename to plugins/nexus-coreui-plugin/src/frontend/src/components/layout/MasterDetail/MasterDetail.test.jsx index 57be734a23..40761957a1 100644 --- a/components/nexus-ui-plugin/src/frontend/src/components/layout/common/MasterDetail/MasterDetail.test.jsx +++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/layout/MasterDetail/MasterDetail.test.jsx @@ -18,11 +18,13 @@ import MasterDetail from './MasterDetail'; import Master from './Master'; import Detail from './Detail'; -import ExtJS from '../../../../interface/ExtJS'; +import {ExtJS} from '@sonatype/nexus-ui-plugin'; -jest.mock('../../../../interface/ExtJS', () => class { - static useHistory = jest.fn(); -}); +jest.mock('@sonatype/nexus-ui-plugin', () => ({ + ExtJS: { + useHistory: jest.fn() + } +})); describe('MasterDetail', () => { it('renders the master view when at the root', () => { diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/layout/MasterDetail/index.js b/plugins/nexus-coreui-plugin/src/frontend/src/components/layout/MasterDetail/index.js new file mode 100644 index 0000000000..0c4252f55a --- /dev/null +++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/layout/MasterDetail/index.js @@ -0,0 +1,20 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2008-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Open Source Version is distributed with Sencha Ext JS pursuant to a FLOSS Exception agreed upon + * between Sonatype, Inc. and Sencha Inc. Sencha Ext JS is licensed under GPL v3 and cannot be redistributed as part of a + * closed source work. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ + +export { default as MasterDetail } from './MasterDetail'; +export { default as Master } from './Master'; +export { default as Detail } from './Detail'; diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/AnonymousSettings/AnonymousSettings.test.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/AnonymousSettings/AnonymousSettings.test.jsx index b283a10768..d8595df064 100644 --- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/AnonymousSettings/AnonymousSettings.test.jsx +++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/AnonymousSettings/AnonymousSettings.test.jsx @@ -96,7 +96,7 @@ describe('AnonymousSettings', () => { it('fetches the values of fields from the API and updates them as expected', async () => { let { - enabledField, userIdField, realmField, discardButton + enabledField, userIdField, realmField, discardButton, saveButton } = selectors; await renderView(); @@ -105,6 +105,8 @@ describe('AnonymousSettings', () => { expect(enabledField()).toBeChecked(); expect(userIdField()).toHaveValue('testUser'); expect(realmField()).toHaveValue('r2'); + + userEvent.click(saveButton()); expect(selectors.queryFormError(TestUtils.NO_CHANGES_MESSAGE)).toBeInTheDocument(); expect(discardButton()).toHaveClass('disabled'); }); @@ -143,6 +145,7 @@ describe('AnonymousSettings', () => { } ); + userEvent.click(saveButton()); expect(selectors.queryFormError(TestUtils.NO_CHANGES_MESSAGE)).toBeInTheDocument(); expect(discardButton()).toHaveClass('disabled'); }); @@ -157,12 +160,10 @@ describe('AnonymousSettings', () => { fireEvent.change(userIdField(), {target: {value: ''}}) await waitFor(() => expect(userIdField()).toHaveValue('')); expect(userIdField()).toHaveErrorMessage(TestUtils.REQUIRED_MESSAGE); - expect(selectors.queryFormError(TestUtils.VALIDATION_ERRORS_MESSAGE)).toBeInTheDocument(); expect(discardButton()).toBeEnabled(); userEvent.click(discardButton()); expect(userIdField()).toHaveValue('testUser'); - expect(selectors.queryFormError(TestUtils.NO_CHANGES_MESSAGE)).toBeInTheDocument(); expect(discardButton()).toHaveClass('disabled'); }); diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/BlobStores/BlobStores.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/BlobStores/BlobStores.jsx index 32b7811c4d..eb6a7b0894 100644 --- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/BlobStores/BlobStores.jsx +++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/BlobStores/BlobStores.jsx @@ -12,7 +12,7 @@ */ import React from 'react'; -import {Detail, Master, MasterDetail} from '@sonatype/nexus-ui-plugin'; +import {Detail, Master, MasterDetail} from '../../../layout/MasterDetail'; import BlobStoresList from './BlobStoresList'; import BlobStoresForm from './BlobStoresForm'; diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/BlobStores/BlobStoresForm.test.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/BlobStores/BlobStoresForm.test.jsx index 8336964e13..a33d3d36e8 100644 --- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/BlobStores/BlobStoresForm.test.jsx +++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/BlobStores/BlobStoresForm.test.jsx @@ -311,7 +311,7 @@ describe('BlobStoresForm', function() { bucket, accessKeyId, secretAccessKey, - endpointURL + endpointURL, } = render(); await waitForElementToBeRemoved(loadingMask); @@ -334,6 +334,7 @@ describe('BlobStoresForm', function() { userEvent.type(accessKeyId(), 'someAccessKey'); expect(accessKeyId()).toHaveValue('someAccessKey'); + userEvent.click(selectors.querySubmitButton()); expect(selectors.queryFormError(TestUtils.VALIDATION_ERRORS_MESSAGE)).toBeInTheDocument(); userEvent.type(secretAccessKey(), 'SomeSecretAccessKey'); @@ -342,6 +343,7 @@ describe('BlobStoresForm', function() { userEvent.type(endpointURL(), 'invalidURL'); expect(endpointURL()).toHaveValue('invalidURL'); + userEvent.click(selectors.querySubmitButton()); expect(selectors.queryFormError(TestUtils.VALIDATION_ERRORS_MESSAGE)).toBeInTheDocument(); userEvent.clear(endpointURL()); @@ -411,7 +413,7 @@ describe('BlobStoresForm', function() { expect(selectors.queryFormError()).not.toBeInTheDocument(); userEvent.click(selectors.getSoftQuota()); - + userEvent.click(selectors.querySubmitButton()); expect(selectors.queryFormError(TestUtils.VALIDATION_ERRORS_MESSAGE)).toBeInTheDocument(); userEvent.selectOptions(softQuotaType(), 'spaceRemainingQuota'); @@ -423,6 +425,7 @@ describe('BlobStoresForm', function() { userEvent.clear(softQuotaLimit()); expect(softQuotaLimit()).toHaveValue(''); + userEvent.click(selectors.querySubmitButton()); expect(selectors.queryFormError(TestUtils.VALIDATION_ERRORS_MESSAGE)).toBeInTheDocument(); @@ -491,6 +494,7 @@ describe('BlobStoresForm', function() { userEvent.selectOptions(typeSelect(), 'S3'); expect(typeSelect()).toHaveValue('s3'); expect(expiration()).toHaveValue('3'); + userEvent.click(selectors.querySubmitButton()); expect(selectors.queryFormError(TestUtils.NO_CHANGES_MESSAGE)).toBeInTheDocument(); @@ -503,6 +507,7 @@ describe('BlobStoresForm', function() { userEvent.type(accessKeyId(), 'someAccessKey'); expect(accessKeyId()).toHaveValue('someAccessKey'); + userEvent.click(selectors.querySubmitButton()); expect(selectors.queryFormError(TestUtils.VALIDATION_ERRORS_MESSAGE)).toBeInTheDocument(); userEvent.type(secretAccessKey(), 'SomeSecretAccessKey'); @@ -511,6 +516,7 @@ describe('BlobStoresForm', function() { userEvent.type(endpointURL(), 'invalidURL'); expect(endpointURL()).toHaveValue('invalidURL'); + userEvent.click(selectors.querySubmitButton()); expect(selectors.queryFormError(TestUtils.VALIDATION_ERRORS_MESSAGE)).toBeInTheDocument(); userEvent.clear(endpointURL()); diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/Bundles/Bundles.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/Bundles/Bundles.jsx index c519aa7036..eb16ee8376 100644 --- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/Bundles/Bundles.jsx +++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/Bundles/Bundles.jsx @@ -12,7 +12,7 @@ */ import React from 'react'; -import {Detail, Master, MasterDetail} from '@sonatype/nexus-ui-plugin'; +import {Detail, Master, MasterDetail} from '../../../layout/MasterDetail'; import BundlesList from './BundlesList'; import BundleDetail from './BundleDetail'; diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPolicies.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPolicies.jsx index 45434cd21b..b68713e050 100644 --- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPolicies.jsx +++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPolicies.jsx @@ -12,7 +12,7 @@ */ import React from 'react'; -import {Detail, Master, MasterDetail} from '@sonatype/nexus-ui-plugin'; +import {Detail, Master, MasterDetail} from '../../../layout/MasterDetail'; import CleanupPoliciesList from './CleanupPoliciesList'; import CleanupPoliciesForm from './CleanupPoliciesForm'; diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesForm.test.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesForm.test.jsx index 559b6c5505..ba683201a8 100644 --- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesForm.test.jsx +++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesForm.test.jsx @@ -226,9 +226,6 @@ describe('CleanupPoliciesForm', function () { ); expect(getCriteriaAssetRegexCheckbox()).toHaveClass('tm-checked'); expect(criteriaAssetRegex()).toHaveValue(EDITABLE_ITEM.criteriaAssetRegex); - expect( - selectors.queryFormError(TestUtils.NO_CHANGES_MESSAGE) - ).toBeInTheDocument(); }); it('renders an error message', async function () { @@ -245,11 +242,8 @@ describe('CleanupPoliciesForm', function () { const {name, format, criteriaLastBlobUpdated, getCriteriaLastBlobUpdatedCheckbox} = selectors; await renderView(); - expect( - selectors.queryFormError(TestUtils.NO_CHANGES_MESSAGE) - ).toBeInTheDocument(); - await TestUtils.changeField(name, EDITABLE_ITEM.name); + userEvent.click(selectors.querySubmitButton()); expect( selectors.queryFormError(TestUtils.VALIDATION_ERRORS_MESSAGE) ).toBeInTheDocument(); @@ -295,6 +289,7 @@ describe('CleanupPoliciesForm', function () { expect(screen.queryByRole('alert')).not.toBeInTheDocument(); await TestUtils.changeField(criteriaLastBlobUpdated, '4.7'); + userEvent.click(selectors.querySubmitButton()); expect( selectors.queryFormError(TestUtils.VALIDATION_ERRORS_MESSAGE) ).toBeInTheDocument(); @@ -315,6 +310,7 @@ describe('CleanupPoliciesForm', function () { expect(screen.queryByRole('alert')).not.toBeInTheDocument(); await TestUtils.changeField(criteriaLastDownloaded, '5.3'); + userEvent.click(selectors.querySubmitButton()); expect( selectors.queryFormError(TestUtils.VALIDATION_ERRORS_MESSAGE) ).toBeInTheDocument(); @@ -631,7 +627,7 @@ describe('CleanupPoliciesForm', function () { it('sets disabled on the button when no repository or criteria is selected', async function () { const {dryRunRepositories, dryRunCreateCSVButton, name, format, - criteriaLastBlobUpdated, getCriteriaLastBlobUpdatedCheckbox} = selectors; + criteriaLastBlobUpdated, getCriteriaLastBlobUpdatedCheckbox, querySubmitButton} = selectors; await renderView(); @@ -649,6 +645,8 @@ describe('CleanupPoliciesForm', function () { expect(selectDropdown).toHaveValue('maven-central'); expect(createButton).toHaveAttribute('aria-disabled', 'true'); + userEvent.click(querySubmitButton()); + expect( selectors.queryFormError(TestUtils.VALIDATION_ERRORS_MESSAGE) ).toBeInTheDocument(); @@ -838,6 +836,7 @@ describe('CleanupPoliciesForm', function () { getCriteriaAssetRegexCheckbox, criteriaAssetRegex, criteriaVersion, + querySubmitButton } = selectors; await renderView(item.name); @@ -855,6 +854,7 @@ describe('CleanupPoliciesForm', function () { ); expect(getCriteriaAssetRegexCheckbox()).toHaveClass('tm-checked'); expect(criteriaAssetRegex()).toHaveValue(item.criteriaAssetRegex); + userEvent.click(querySubmitButton()); expect( selectors.queryFormError(TestUtils.NO_CHANGES_MESSAGE) ).toBeInTheDocument(); diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/ContentSelectors/ContentSelectors.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/ContentSelectors/ContentSelectors.jsx index 52e99642bd..f69e167fda 100644 --- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/ContentSelectors/ContentSelectors.jsx +++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/ContentSelectors/ContentSelectors.jsx @@ -12,7 +12,7 @@ */ import React from 'react'; -import {Detail, Master, MasterDetail} from '@sonatype/nexus-ui-plugin'; +import {Detail, Master, MasterDetail} from '../../../layout/MasterDetail'; import ContentSelectorsList from './ContentSelectorsList'; import ContentSelectorsDetails from './ContentSelectorsDetails'; diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/ContentSelectors/ContentSelectorsForm.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/ContentSelectors/ContentSelectorsForm.jsx index a68aba3aaf..a328bb172e 100644 --- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/ContentSelectors/ContentSelectorsForm.jsx +++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/ContentSelectors/ContentSelectorsForm.jsx @@ -16,7 +16,6 @@ import {faTrash} from '@fortawesome/free-solid-svg-icons'; import { Section, - Textarea, FormUtils, ExtJS } from '@sonatype/nexus-ui-plugin'; @@ -43,10 +42,6 @@ export default function ContentSelectorsForm({service, onDone}) { const canDelete = ExtJS.checkPermission('nexus:selectors:delete'); const isEdit = Boolean(pristineData.name); - function update(event) { - send('UPDATE', {data: {[event.target.name]: event.target.value}}); - } - function cancel() { onDone(); } @@ -59,13 +54,13 @@ export default function ContentSelectorsForm({service, onDone}) {
- - {UIStrings.SETTINGS.DELETE_BUTTON_LABEL} - - } + onCancel={cancel} + additionalFooterBtns={isEdit && canDelete && + + + {UIStrings.SETTINGS.DELETE_BUTTON_LABEL} + + } > {hasData && !Boolean(pristineData.name) && @@ -87,12 +82,13 @@ export default function ContentSelectorsForm({service, onDone}) { onChange={FormUtils.handleUpdate('description', send)}/> -