From 91d75269bac6beb19aa3e06347b7e7fbcd9a8f82 Mon Sep 17 00:00:00 2001 From: John Casey Date: Fri, 19 Jul 2019 14:07:53 -0500 Subject: [PATCH] Fix path-cleanup submit to drain service, not to executor service. Also, adding a regression test to ensure this doesn't happen again. --- .../core/change/StoreContentListener.java | 2 +- ...rshipAddMayDisruptMetadataRefreshTest.java | 117 ++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 ftests/core/src/main/java/org/commonjava/indy/ftest/core/content/GroupMembershipAddMayDisruptMetadataRefreshTest.java diff --git a/core/src/main/java/org/commonjava/indy/core/change/StoreContentListener.java b/core/src/main/java/org/commonjava/indy/core/change/StoreContentListener.java index 40b8d94d5d..bf2fd40b6a 100644 --- a/core/src/main/java/org/commonjava/indy/core/change/StoreContentListener.java +++ b/core/src/main/java/org/commonjava/indy/core/change/StoreContentListener.java @@ -269,7 +269,7 @@ private void clearPaths( final Set keys, Predicate pat logger.debug( "Submit clean job for origin: {}", origin ); final Set affectedGroups = affected; - cleanupExecutor.submit( clearPathsProcessor( origin, pathFilter, affectedGroups, deleteOriginPath ) ); + clearService.submit( clearPathsProcessor( origin, pathFilter, affectedGroups, deleteOriginPath ) ); } ); drainAndCount( clearService, "stores: " + keys ); diff --git a/ftests/core/src/main/java/org/commonjava/indy/ftest/core/content/GroupMembershipAddMayDisruptMetadataRefreshTest.java b/ftests/core/src/main/java/org/commonjava/indy/ftest/core/content/GroupMembershipAddMayDisruptMetadataRefreshTest.java new file mode 100644 index 0000000000..d3ee6d7b7f --- /dev/null +++ b/ftests/core/src/main/java/org/commonjava/indy/ftest/core/content/GroupMembershipAddMayDisruptMetadataRefreshTest.java @@ -0,0 +1,117 @@ +/** + * Copyright (C) 2011-2018 Red Hat, Inc. (https://github.com/Commonjava/indy) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.commonjava.indy.ftest.core.content; + +import org.commonjava.indy.ftest.core.category.BytemanTest; +import org.commonjava.indy.test.fixture.core.CoreServerFixture; +import org.jboss.byteman.contrib.bmunit.BMRule; +import org.jboss.byteman.contrib.bmunit.BMRules; +import org.jboss.byteman.contrib.bmunit.BMUnitConfig; +import org.jboss.byteman.contrib.bmunit.BMUnitRunner; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +import java.io.IOException; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +/** + * GIVEN: + *
    + *
  • RemoteRepositories A, B, and C, each containing metadata paths P
  • + *
  • Group G with A and B members
  • + *
+ * + *
+ * WHEN: + *
    + *
  • Actions of Users coordinated by Byteman to expose race condition
  • + *
  • User 1 START
  • + *
  • User 1 GET: path P from Group G
  • + *
  • RENDEZVOUS: User 1 END then User 2 START
  • + *
  • User 2 POST: add C to Group G membership
  • + *
  • RENDEZVOUS: User 2 END then User 3 START
  • + *
  • User 3 GET: path P from Group G
  • + *
  • User 3 END
  • + *
+ * + *
+ * THEN: + *
    + *
  • User 1 request gets AB content for P in G
  • + *
  • User 2 request deletes path P maven-metadata.xml in G
  • + *
  • User 3 request gets ABC content for P in G
  • + *
+ */ +@RunWith( BMUnitRunner.class ) +@BMUnitConfig( debug = true ) +public class GroupMembershipAddMayDisruptMetadataRefreshTest + extends GroupMembershipChangeUpdateMetadataTest +{ + /* @formatter:off */ + @BMRules( rules = { + @BMRule( + name = "Enable slow list processing", + targetClass = "TestStartTrigger", + targetMethod = "run", + targetLocation = "EXIT", + action = "debug(\"Setting up slow-down for list processing\"); flag(\"ready\")" ), + @BMRule( + name = "Slow list processing when ready", + targetClass = "StoreChangeUtil", + targetMethod = "listPathsAnd", + condition = "flagged(\"ready\")", + targetLocation = "ENTRY", + action = "debug(\"Slowing file listing processor...\"); Thread.sleep(2000)" ), + } ) + /* @formatter:on */ + @Test + @Category( BytemanTest.class ) + public void run() + throws Exception + { + prepare(); + + logger.info("\n\n\n\n\n\nSTART Test Process\n\n\n\n"); + + new TestStartTrigger().run(); + + String beforeMetadata = new GroupMetaCallable( path_P ).call(); + + String retCode = new GroupAddCallable( remoteRepositoryC.getKey() ).call(); + + String afterMetadata = new GroupMetaCallable( path_P ).call(); + + assertThat( "User 1 INCORRECT", beforeMetadata, equalTo( mergedContent_AB ) ); + assertThat( "User 2 INCORRECT", retCode, equalTo( "OK" ) ); + assertThat( "User 3 INCORRECT", afterMetadata, equalTo( mergedContent_ABC ) ); + } + + @Override + protected void initTestConfig( final CoreServerFixture fixture ) + throws IOException + { + super.initTestConfig( fixture ); + writeConfigFile( "conf.d/threadpools.conf", "[threadpools]\nenabled=true" ); + } + + private static final class TestStartTrigger implements Runnable + { + public void run(){} + } +}