GameTestRunner.java

net.minecraft.gametest.framework.GameTestRunner

信息

  • 全限定名:net.minecraft.gametest.framework.GameTestRunner
  • 类型:public class
  • 包:net.minecraft.gametest.framework
  • 源码路径:src/main/java/net/minecraft/gametest/framework/GameTestRunner.java
  • 起始行号:L20
  • 职责:

    TODO

字段/常量

  • DEFAULT_TESTS_PER_ROW

    • 类型: int
    • 修饰符: public static final
    • 源码定位: L21
    • 说明:

      TODO

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L22
    • 说明:

      TODO

  • level

    • 类型: ServerLevel
    • 修饰符: private final
    • 源码定位: L23
    • 说明:

      TODO

  • testTicker

    • 类型: GameTestTicker
    • 修饰符: private final
    • 源码定位: L24
    • 说明:

      TODO

  • allTestInfos

    • 类型: List<GameTestInfo>
    • 修饰符: private final
    • 源码定位: L25
    • 说明:

      TODO

  • batches

    • 类型: ImmutableList<GameTestBatch>
    • 修饰符: private
    • 源码定位: L26
    • 说明:

      TODO

  • batchListeners

    • 类型: List<GameTestBatchListener>
    • 修饰符: private final
    • 源码定位: L27
    • 说明:

      TODO

  • scheduledForRerun

    • 类型: List<GameTestInfo>
    • 修饰符: private final
    • 源码定位: L28
    • 说明:

      TODO

  • testBatcher

    • 类型: GameTestRunner.GameTestBatcher
    • 修饰符: private final
    • 源码定位: L29
    • 说明:

      TODO

  • stopped

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L30
    • 说明:

      TODO

  • currentEnvironment

    • 类型: TestEnvironmentDefinition.Activation<?>
    • 修饰符: private
    • 源码定位: L31
    • 说明:

      TODO

  • existingStructureSpawner

    • 类型: GameTestRunner.StructureSpawner
    • 修饰符: private final
    • 源码定位: L32
    • 说明:

      TODO

  • newStructureSpawner

    • 类型: GameTestRunner.StructureSpawner
    • 修饰符: private final
    • 源码定位: L33
    • 说明:

      TODO

  • haltOnError

    • 类型: boolean
    • 修饰符: private final
    • 源码定位: L34
    • 说明:

      TODO

  • clearBetweenBatches

    • 类型: boolean
    • 修饰符: private final
    • 源码定位: L35
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.gametest.framework.GameTestRunner.Builder

    • 类型: class
    • 修饰符: public static
    • 源码定位: L191
    • 说明:

      TODO

  • net.minecraft.gametest.framework.GameTestRunner.GameTestBatcher

    • 类型: interface
    • 修饰符: public
    • 源码定位: L253
    • 说明:

      TODO

  • net.minecraft.gametest.framework.GameTestRunner.StructureSpawner

    • 类型: interface
    • 修饰符: public
    • 源码定位: L257
    • 说明:

      TODO

构造器

protected GameTestRunner(GameTestRunner.GameTestBatcher batcher, Collection<GameTestBatch> batches, ServerLevel level, GameTestTicker testTicker, GameTestRunner.StructureSpawner existingStructureSpawner, GameTestRunner.StructureSpawner newStructureSpawner, boolean haltOnError, boolean clearBetweenBatches) @ L37

  • 构造器名:GameTestRunner
  • 源码定位:L37
  • 修饰符:protected

参数:

  • batcher: GameTestRunner.GameTestBatcher
  • batches: Collection
  • level: ServerLevel
  • testTicker: GameTestTicker
  • existingStructureSpawner: GameTestRunner.StructureSpawner
  • newStructureSpawner: GameTestRunner.StructureSpawner
  • haltOnError: boolean
  • clearBetweenBatches: boolean

说明:

TODO

方法

下面的方法块按源码顺序生成。

public List<GameTestInfo> getTestInfos() @ L60

  • 方法名:getTestInfos
  • 源码定位:L60
  • 返回类型:List
  • 修饰符:public

参数:

说明:

TODO

public void start() @ L64

  • 方法名:start
  • 源码定位:L64
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void stop() @ L69

  • 方法名:stop
  • 源码定位:L69
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void rerunTest(GameTestInfo info) @ L76

  • 方法名:rerunTest
  • 源码定位:L76
  • 返回类型:void
  • 修饰符:public

参数:

  • info: GameTestInfo

说明:

TODO

private void runBatch(int batchIndex) @ L86

  • 方法名:runBatch
  • 源码定位:L86
  • 返回类型:void
  • 修饰符:private

参数:

  • batchIndex: int

说明:

TODO

private void endCurrentEnvironment() @ L159

  • 方法名:endCurrentEnvironment
  • 源码定位:L159
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

private void runScheduledRerunTests() @ L166

  • 方法名:runScheduledRerunTests
  • 源码定位:L166
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

public void addListener(GameTestBatchListener listener) @ L179

  • 方法名:addListener
  • 源码定位:L179
  • 返回类型:void
  • 修饰符:public

参数:

  • listener: GameTestBatchListener

说明:

TODO

private Collection<GameTestInfo> createStructuresForBatch(Collection<GameTestInfo> batch) @ L183

  • 方法名:createStructuresForBatch
  • 源码定位:L183
  • 返回类型:Collection
  • 修饰符:private

参数:

  • batch: Collection

说明:

TODO

private Optional<GameTestInfo> spawn(GameTestInfo testInfo) @ L187

  • 方法名:spawn
  • 源码定位:L187
  • 返回类型:Optional
  • 修饰符:private

参数:

  • testInfo: GameTestInfo

说明:

TODO

代码

public class GameTestRunner {
    public static final int DEFAULT_TESTS_PER_ROW = 8;
    private static final Logger LOGGER = LogUtils.getLogger();
    private final ServerLevel level;
    private final GameTestTicker testTicker;
    private final List<GameTestInfo> allTestInfos;
    private ImmutableList<GameTestBatch> batches;
    private final List<GameTestBatchListener> batchListeners = Lists.newArrayList();
    private final List<GameTestInfo> scheduledForRerun = Lists.newArrayList();
    private final GameTestRunner.GameTestBatcher testBatcher;
    private boolean stopped = true;
    private TestEnvironmentDefinition.@Nullable Activation<?> currentEnvironment;
    private final GameTestRunner.StructureSpawner existingStructureSpawner;
    private final GameTestRunner.StructureSpawner newStructureSpawner;
    private final boolean haltOnError;
    private final boolean clearBetweenBatches;
 
    protected GameTestRunner(
        GameTestRunner.GameTestBatcher batcher,
        Collection<GameTestBatch> batches,
        ServerLevel level,
        GameTestTicker testTicker,
        GameTestRunner.StructureSpawner existingStructureSpawner,
        GameTestRunner.StructureSpawner newStructureSpawner,
        boolean haltOnError,
        boolean clearBetweenBatches
    ) {
        this.level = level;
        this.testTicker = testTicker;
        this.testBatcher = batcher;
        this.existingStructureSpawner = existingStructureSpawner;
        this.newStructureSpawner = newStructureSpawner;
        this.batches = ImmutableList.copyOf(batches);
        this.haltOnError = haltOnError;
        this.clearBetweenBatches = clearBetweenBatches;
        this.allTestInfos = this.batches.stream().flatMap(batch -> batch.gameTestInfos().stream()).collect(Util.toMutableList());
        testTicker.setRunner(this);
        this.allTestInfos.forEach(info -> info.addListener(new ReportGameListener()));
    }
 
    public List<GameTestInfo> getTestInfos() {
        return this.allTestInfos;
    }
 
    public void start() {
        this.stopped = false;
        this.runBatch(0);
    }
 
    public void stop() {
        this.stopped = true;
        if (this.currentEnvironment != null) {
            this.endCurrentEnvironment();
        }
    }
 
    public void rerunTest(GameTestInfo info) {
        GameTestInfo copy = info.copyReset();
        info.getListeners().forEach(listener -> listener.testAddedForRerun(info, copy, this));
        this.allTestInfos.add(copy);
        this.scheduledForRerun.add(copy);
        if (this.stopped) {
            this.runScheduledRerunTests();
        }
    }
 
    private void runBatch(int batchIndex) {
        if (batchIndex >= this.batches.size()) {
            this.endCurrentEnvironment();
            this.runScheduledRerunTests();
        } else {
            if (batchIndex > 0 && this.clearBetweenBatches) {
                GameTestBatch lastBatch = this.batches.get(batchIndex - 1);
                lastBatch.gameTestInfos().forEach(gameTestInfo -> {
                    TestInstanceBlockEntity testInstanceBlockEntity = gameTestInfo.getTestInstanceBlockEntity();
                    StructureUtils.clearSpaceForStructure(testInstanceBlockEntity.getTestBoundingBox(), this.level);
                    this.level.destroyBlock(testInstanceBlockEntity.getBlockPos(), false);
                });
            }
 
            final GameTestBatch currentBatch = this.batches.get(batchIndex);
            this.existingStructureSpawner.onBatchStart(this.level);
            this.newStructureSpawner.onBatchStart(this.level);
            Collection<GameTestInfo> testInfosForThisBatch = this.createStructuresForBatch(currentBatch.gameTestInfos());
            LOGGER.info(
                "Running test environment '{}' batch {} ({} tests)...",
                currentBatch.environment().getRegisteredName(),
                currentBatch.index(),
                testInfosForThisBatch.size()
            );
            this.endCurrentEnvironment();
            this.currentEnvironment = TestEnvironmentDefinition.activate(currentBatch.environment().value(), this.level);
            this.batchListeners.forEach(listener -> listener.testBatchStarting(currentBatch));
            final MultipleTestTracker currentBatchTracker = new MultipleTestTracker();
            testInfosForThisBatch.forEach(currentBatchTracker::addTestToTrack);
            currentBatchTracker.addListener(new GameTestListener() {
                {
                    Objects.requireNonNull(GameTestRunner.this);
                }
 
                private void testCompleted(GameTestInfo testInfo) {
                    if (currentBatchTracker.isDone()) {
                        GameTestRunner.this.batchListeners.forEach(listener -> listener.testBatchFinished(currentBatch));
                        LongSet forcedChunks = new LongArraySet(GameTestRunner.this.level.getForceLoadedChunks());
                        forcedChunks.forEach(pos -> GameTestRunner.this.level.setChunkForced(ChunkPos.getX(pos), ChunkPos.getZ(pos), false));
                        GameTestRunner.this.runBatch(batchIndex + 1);
                    }
                }
 
                @Override
                public void testStructureLoaded(GameTestInfo testInfo) {
                }
 
                @Override
                public void testPassed(GameTestInfo testInfo, GameTestRunner runner) {
                    testInfo.getTestInstanceBlockEntity().removeBarriers();
                    this.testCompleted(testInfo);
                }
 
                @Override
                public void testFailed(GameTestInfo testInfo, GameTestRunner runner) {
                    if (GameTestRunner.this.haltOnError) {
                        GameTestRunner.this.endCurrentEnvironment();
                        LongSet forcedChunks = new LongArraySet(GameTestRunner.this.level.getForceLoadedChunks());
                        forcedChunks.forEach(pos -> GameTestRunner.this.level.setChunkForced(ChunkPos.getX(pos), ChunkPos.getZ(pos), false));
                        GameTestTicker.SINGLETON.clear();
                    } else {
                        this.testCompleted(testInfo);
                    }
                }
 
                @Override
                public void testAddedForRerun(GameTestInfo original, GameTestInfo copy, GameTestRunner runner) {
                }
            });
            testInfosForThisBatch.forEach(this.testTicker::add);
        }
    }
 
    private void endCurrentEnvironment() {
        if (this.currentEnvironment != null) {
            this.currentEnvironment.teardown();
            this.currentEnvironment = null;
        }
    }
 
    private void runScheduledRerunTests() {
        if (!this.scheduledForRerun.isEmpty()) {
            LOGGER.info("Starting re-run of tests: {}", this.scheduledForRerun.stream().map(info -> info.id().toString()).collect(Collectors.joining(", ")));
            this.batches = ImmutableList.copyOf(this.testBatcher.batch(this.scheduledForRerun));
            this.scheduledForRerun.clear();
            this.stopped = false;
            this.runBatch(0);
        } else {
            this.batches = ImmutableList.of();
            this.stopped = true;
        }
    }
 
    public void addListener(GameTestBatchListener listener) {
        this.batchListeners.add(listener);
    }
 
    private Collection<GameTestInfo> createStructuresForBatch(Collection<GameTestInfo> batch) {
        return batch.stream().map(this::spawn).flatMap(Optional::stream).toList();
    }
 
    private Optional<GameTestInfo> spawn(GameTestInfo testInfo) {
        return testInfo.getTestBlockPos() == null ? this.newStructureSpawner.spawnStructure(testInfo) : this.existingStructureSpawner.spawnStructure(testInfo);
    }
 
    public static class Builder {
        private final ServerLevel level;
        private final GameTestTicker testTicker = GameTestTicker.SINGLETON;
        private GameTestRunner.GameTestBatcher batcher = GameTestBatchFactory.fromGameTestInfo();
        private GameTestRunner.StructureSpawner existingStructureSpawner = GameTestRunner.StructureSpawner.IN_PLACE;
        private GameTestRunner.StructureSpawner newStructureSpawner = GameTestRunner.StructureSpawner.NOT_SET;
        private final Collection<GameTestBatch> batches;
        private boolean haltOnError = false;
        private boolean clearBetweenBatches = false;
 
        private Builder(Collection<GameTestBatch> batches, ServerLevel level) {
            this.batches = batches;
            this.level = level;
        }
 
        public static GameTestRunner.Builder fromBatches(Collection<GameTestBatch> batches, ServerLevel level) {
            return new GameTestRunner.Builder(batches, level);
        }
 
        public static GameTestRunner.Builder fromInfo(Collection<GameTestInfo> tests, ServerLevel level) {
            return fromBatches(GameTestBatchFactory.fromGameTestInfo().batch(tests), level);
        }
 
        public GameTestRunner.Builder haltOnError() {
            this.haltOnError = true;
            return this;
        }
 
        public GameTestRunner.Builder clearBetweenBatches() {
            this.clearBetweenBatches = true;
            return this;
        }
 
        public GameTestRunner.Builder newStructureSpawner(GameTestRunner.StructureSpawner structureSpawner) {
            this.newStructureSpawner = structureSpawner;
            return this;
        }
 
        public GameTestRunner.Builder existingStructureSpawner(StructureGridSpawner spawner) {
            this.existingStructureSpawner = spawner;
            return this;
        }
 
        public GameTestRunner.Builder batcher(GameTestRunner.GameTestBatcher batcher) {
            this.batcher = batcher;
            return this;
        }
 
        public GameTestRunner build() {
            return new GameTestRunner(
                this.batcher,
                this.batches,
                this.level,
                this.testTicker,
                this.existingStructureSpawner,
                this.newStructureSpawner,
                this.haltOnError,
                this.clearBetweenBatches
            );
        }
    }
 
    public interface GameTestBatcher {
        Collection<GameTestBatch> batch(Collection<GameTestInfo> infos);
    }
 
    public interface StructureSpawner {
        GameTestRunner.StructureSpawner IN_PLACE = testInfo -> Optional.ofNullable(testInfo.prepareTestStructure()).map(e -> e.startExecution(1));
        GameTestRunner.StructureSpawner NOT_SET = testInfo -> Optional.empty();
 
        Optional<GameTestInfo> spawnStructure(GameTestInfo testInfo);
 
        default void onBatchStart(ServerLevel level) {
        }
    }
}

引用的其他类