| // Copyright 2021 The Bazel Authors. All rights reserved. |
| // |
| // 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 com.google.devtools.build.lib.bazel.bzlmod; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createDepSpec; |
| import static com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.createModuleKey; |
| import static org.junit.Assert.assertThrows; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.devtools.build.lib.bazel.bzlmod.BzlmodTestUtil.InterimModuleBuilder; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| /** Tests for {@link Selection}. */ |
| @RunWith(JUnit4.class) |
| public class SelectionTest { |
| |
| @Test |
| public void diamond_simple() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()) |
| .buildOrThrow(); |
| |
| Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()) |
| .inOrder(); |
| |
| assertThat(selectionResult.getUnprunedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()); |
| } |
| |
| @Test |
| public void diamond_withIgnoredNonAffectingMaxCompatibilityLevel() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 3)) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()) |
| .buildOrThrow(); |
| |
| Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 3)) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()) |
| .inOrder(); |
| |
| assertThat(selectionResult.getUnprunedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 3)) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()); |
| } |
| |
| @Test |
| public void diamond_withSelectedNonAffectingMaxCompatibilityLevel() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createDepSpec("ddd", "2.0", 4)) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()) |
| .buildOrThrow(); |
| |
| Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd_from_ccc", createDepSpec("ddd", "2.0", 4)) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()) |
| .inOrder(); |
| |
| assertThat(selectionResult.getUnprunedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd_from_ccc", createDepSpec("ddd", "2.0", 4)) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0", 1).buildEntry()); |
| } |
| |
| @Test |
| public void diamond_withFurtherRemoval() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb", createModuleKey("bbb", "1.0")) |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd", createModuleKey("ddd", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd", createModuleKey("ddd", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ddd", "1.0") |
| .addDep("eee", createModuleKey("eee", "1.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "2.0").buildEntry()) |
| // Only D@1.0 needs E. When D@1.0 is removed, E should be gone as well (even though |
| // E@1.0 is selected for E). |
| .put(InterimModuleBuilder.create("eee", "1.0").buildEntry()) |
| .build(); |
| |
| Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb", createModuleKey("bbb", "1.0")) |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd", createModuleKey("ddd", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd", createModuleKey("ddd", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0").buildEntry()) |
| .inOrder(); |
| |
| assertThat(selectionResult.getUnprunedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb", createModuleKey("bbb", "1.0")) |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd", createModuleKey("ddd", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd", createModuleKey("ddd", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0").buildEntry(), |
| InterimModuleBuilder.create("ddd", "1.0") |
| .addDep("eee", createModuleKey("eee", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("eee", "1.0").buildEntry()); |
| } |
| |
| @Test |
| public void circularDependencyDueToSelection() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb", createModuleKey("bbb", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("bbb", createModuleKey("bbb", "1.0-pre")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0-pre") |
| .addDep("ddd", createModuleKey("ddd", "1.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "1.0").buildEntry()) |
| .buildOrThrow(); |
| |
| Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb", createModuleKey("bbb", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("bbb", createModuleKey("bbb", "1.0")) |
| .addOriginalDep("bbb", createModuleKey("bbb", "1.0-pre")) |
| .buildEntry()) |
| .inOrder(); |
| // D is completely gone. |
| |
| assertThat(selectionResult.getUnprunedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb", createModuleKey("bbb", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("bbb", createModuleKey("bbb", "1.0")) |
| .addOriginalDep("bbb", createModuleKey("bbb", "1.0-pre")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0-pre") |
| .addDep("ddd", createModuleKey("ddd", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "1.0").buildEntry()); |
| } |
| |
| @Test |
| public void differentCompatibilityLevelIsRejected() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) |
| .buildOrThrow(); |
| |
| ExternalDepsException e = |
| assertThrows( |
| ExternalDepsException.class, |
| () -> Selection.run(depGraph, /* overrides= */ ImmutableMap.of())); |
| String error = e.getMessage(); |
| assertThat(error).contains("bbb@1.0 depends on ddd@1.0 with compatibility level 1"); |
| assertThat(error).contains("ccc@2.0 depends on ddd@2.0 with compatibility level 2"); |
| assertThat(error).contains("which is different"); |
| } |
| |
| @Test |
| public void differentCompatibilityLevelWithMaxCompatibilityLevelIsRejected() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createDepSpec("ddd", "2.0", 3)) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) |
| .buildOrThrow(); |
| |
| ExternalDepsException e = |
| assertThrows( |
| ExternalDepsException.class, |
| () -> Selection.run(depGraph, /* overrides= */ ImmutableMap.of())); |
| String error = e.getMessage(); |
| assertThat(error).contains("bbb@1.0 depends on ddd@1.0 with compatibility level 1"); |
| assertThat(error).contains("ccc@2.0 depends on ddd@2.0 with compatibility level 2"); |
| assertThat(error).contains("which is different"); |
| } |
| |
| @Test |
| public void maxCompatibilityBasedSelection() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 2)) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) |
| .buildOrThrow(); |
| |
| Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 2)) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) |
| .inOrder(); |
| |
| assertThat(selectionResult.getUnprunedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 2)) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()); |
| } |
| |
| @Test |
| public void maxCompatibilityBasedSelection_sameVersion() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createDepSpec("ddd", "2.0", 3)) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) |
| .buildOrThrow(); |
| |
| Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd_from_bbb", createDepSpec("ddd", "2.0", 3)) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) |
| .inOrder(); |
| |
| assertThat(selectionResult.getUnprunedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "2.0")) |
| .addOriginalDep("ddd_from_bbb", createDepSpec("ddd", "2.0", 3)) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()); |
| } |
| |
| @Test |
| public void maxCompatibilityBasedSelection_limitedToMax() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createDepSpec("ddd", "1.0", 2)) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "3.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "3.0", 3).buildEntry()) |
| .buildOrThrow(); |
| |
| ExternalDepsException e = |
| assertThrows( |
| ExternalDepsException.class, |
| () -> Selection.run(depGraph, /* overrides= */ ImmutableMap.of())); |
| String error = e.getMessage(); |
| assertThat(error).contains("bbb@1.0 depends on ddd@1.0 with compatibility level 1"); |
| assertThat(error).contains("ccc@2.0 depends on ddd@3.0 with compatibility level 3"); |
| assertThat(error).contains("which is different"); |
| } |
| |
| @Test |
| public void maxCompatibilityBasedSelection_unreferencedNotSelected() throws Exception { |
| // aaa 1.0 -> bbb 1.0 -> ccc 2.0 |
| // \-> ccc 1.0 (max_compatibility_level=2) |
| // \-> ddd 1.0 -> bbb 1.1 |
| // \-> eee 1.0 -> ccc 1.1 |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", "1.0") |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb", createModuleKey("bbb", "1.0")) |
| .addDep("ccc", createDepSpec("ccc", "1.0", 2)) |
| .addDep("ddd", createModuleKey("ddd", "1.0")) |
| .addDep("eee", createModuleKey("eee", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ddd", "1.0") |
| .addDep("bbb", createModuleKey("bbb", "1.1")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("bbb", "1.1").buildEntry()) |
| .put( |
| InterimModuleBuilder.create("eee", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.1")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "1.1", 1).buildEntry()) |
| .buildOrThrow(); |
| |
| // After selection, ccc 2.0 is gone, so ccc 1.0 (max_compatibility_level=2) doesn't upgrade to |
| // ccc 2.0, and only upgrades to ccc 1.1 |
| // aaa 1.0 -> bbb 1.1 |
| // \-> ccc 1.1 |
| // \-> ddd 1.0 -> bbb 1.1 |
| // \-> eee 1.0 -> ccc 1.1 |
| Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", "1.0") |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb", createModuleKey("bbb", "1.1")) |
| .addOriginalDep("bbb", createModuleKey("bbb", "1.0")) |
| .addDep("ccc", createModuleKey("ccc", "1.1")) |
| .addOriginalDep("ccc", createDepSpec("ccc", "1.0", 2)) |
| .addDep("ddd", createModuleKey("ddd", "1.0")) |
| .addDep("eee", createModuleKey("eee", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.1").buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.1", 1).buildEntry(), |
| InterimModuleBuilder.create("ddd", "1.0") |
| .addDep("bbb", createModuleKey("bbb", "1.1")) |
| .buildEntry(), |
| InterimModuleBuilder.create("eee", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.1")) |
| .buildEntry()) |
| .inOrder(); |
| |
| assertThat(selectionResult.getUnprunedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", "1.0") |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb", createModuleKey("bbb", "1.1")) |
| .addOriginalDep("bbb", createModuleKey("bbb", "1.0")) |
| .addDep("ccc", createModuleKey("ccc", "1.1")) |
| .addOriginalDep("ccc", createDepSpec("ccc", "1.0", 2)) |
| .addDep("ddd", createModuleKey("ddd", "1.0")) |
| .addDep("eee", createModuleKey("eee", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.1").buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.1", 1).buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry(), |
| InterimModuleBuilder.create("ddd", "1.0") |
| .addDep("bbb", createModuleKey("bbb", "1.1")) |
| .buildEntry(), |
| InterimModuleBuilder.create("eee", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.1")) |
| .buildEntry()); |
| } |
| |
| @Test |
| public void differentCompatibilityLevelIsOkIfUnreferenced() throws Exception { |
| // aaa 1.0 -> bbb 1.0 -> ccc 2.0 |
| // \-> ccc 1.0 |
| // \-> ddd 1.0 -> bbb 1.1 |
| // \-> eee 1.0 -> ccc 1.1 |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", "1.0") |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb", createModuleKey("bbb", "1.0")) |
| .addDep("ccc", createModuleKey("ccc", "1.0")) |
| .addDep("ddd", createModuleKey("ddd", "1.0")) |
| .addDep("eee", createModuleKey("eee", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ddd", "1.0") |
| .addDep("bbb", createModuleKey("bbb", "1.1")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("bbb", "1.1").buildEntry()) |
| .put( |
| InterimModuleBuilder.create("eee", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.1")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "1.1", 1).buildEntry()) |
| .buildOrThrow(); |
| |
| // After selection, ccc 2.0 is gone, so we're okay. |
| // aaa 1.0 -> bbb 1.1 |
| // \-> ccc 1.1 |
| // \-> ddd 1.0 -> bbb 1.1 |
| // \-> eee 1.0 -> ccc 1.1 |
| Selection.Result selectionResult = Selection.run(depGraph, /* overrides= */ ImmutableMap.of()); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", "1.0") |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb", createModuleKey("bbb", "1.1")) |
| .addOriginalDep("bbb", createModuleKey("bbb", "1.0")) |
| .addDep("ccc", createModuleKey("ccc", "1.1")) |
| .addOriginalDep("ccc", createModuleKey("ccc", "1.0")) |
| .addDep("ddd", createModuleKey("ddd", "1.0")) |
| .addDep("eee", createModuleKey("eee", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.1").buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.1", 1).buildEntry(), |
| InterimModuleBuilder.create("ddd", "1.0") |
| .addDep("bbb", createModuleKey("bbb", "1.1")) |
| .buildEntry(), |
| InterimModuleBuilder.create("eee", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.1")) |
| .buildEntry()) |
| .inOrder(); |
| |
| assertThat(selectionResult.getUnprunedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", "1.0") |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb", createModuleKey("bbb", "1.1")) |
| .addOriginalDep("bbb", createModuleKey("bbb", "1.0")) |
| .addDep("ccc", createModuleKey("ccc", "1.1")) |
| .addOriginalDep("ccc", createModuleKey("ccc", "1.0")) |
| .addDep("ddd", createModuleKey("ddd", "1.0")) |
| .addDep("eee", createModuleKey("eee", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.1").buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.1", 1).buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry(), |
| InterimModuleBuilder.create("ddd", "1.0") |
| .addDep("bbb", createModuleKey("bbb", "1.1")) |
| .buildEntry(), |
| InterimModuleBuilder.create("eee", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.1")) |
| .buildEntry()); |
| } |
| |
| @Test |
| public void multipleVersionOverride_fork_allowedVersionMissingInDepGraph() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb1", createModuleKey("bbb", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb", "2.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("bbb", "1.0").buildEntry()) |
| .put(InterimModuleBuilder.create("bbb", "2.0").buildEntry()) |
| .buildOrThrow(); |
| ImmutableMap<String, ModuleOverride> overrides = |
| ImmutableMap.of( |
| "bbb", |
| MultipleVersionOverride.create( |
| ImmutableList.of(Version.parse("1.0"), Version.parse("2.0"), Version.parse("3.0")), |
| "")); |
| |
| ExternalDepsException e = |
| assertThrows(ExternalDepsException.class, () -> Selection.run(depGraph, overrides)); |
| assertThat(e) |
| .hasMessageThat() |
| .contains( |
| "multiple_version_override for module bbb contains version 3.0, but it doesn't exist in" |
| + " the dependency graph"); |
| } |
| |
| @Test |
| public void multipleVersionOverride_fork_goodCase() throws Exception { |
| // For more complex good cases, see the "diamond" test cases below. |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb1", createModuleKey("bbb", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb", "2.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("bbb", "1.0").buildEntry()) |
| .put(InterimModuleBuilder.create("bbb", "2.0").buildEntry()) |
| .buildOrThrow(); |
| ImmutableMap<String, ModuleOverride> overrides = |
| ImmutableMap.of( |
| "bbb", |
| MultipleVersionOverride.create( |
| ImmutableList.of(Version.parse("1.0"), Version.parse("2.0")), "")); |
| |
| Selection.Result selectionResult = Selection.run(depGraph, overrides); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb1", createModuleKey("bbb", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0").buildEntry(), |
| InterimModuleBuilder.create("bbb", "2.0").buildEntry()) |
| .inOrder(); |
| |
| assertThat(selectionResult.getUnprunedDepGraph()) |
| .isEqualTo(selectionResult.getResolvedDepGraph()); |
| } |
| |
| @Test |
| public void multipleVersionOverride_fork_sameVersionUsedTwice() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb1", createModuleKey("bbb", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb", "1.3")) |
| .addDep("bbb3", createModuleKey("bbb", "1.5")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("bbb", "1.0").buildEntry()) |
| .put(InterimModuleBuilder.create("bbb", "1.3").buildEntry()) |
| .put(InterimModuleBuilder.create("bbb", "1.5").buildEntry()) |
| .buildOrThrow(); |
| ImmutableMap<String, ModuleOverride> overrides = |
| ImmutableMap.of( |
| "bbb", |
| MultipleVersionOverride.create( |
| ImmutableList.of(Version.parse("1.0"), Version.parse("1.5")), "")); |
| |
| ExternalDepsException e = |
| assertThrows(ExternalDepsException.class, () -> Selection.run(depGraph, overrides)); |
| assertThat(e) |
| .hasMessageThat() |
| .containsMatch( |
| "aaa@_ depends on bbb@1.5 at least twice \\(with repo names (bbb2 and bbb3)|(bbb3 and" |
| + " bbb2)\\)"); |
| } |
| |
| @Test |
| public void multipleVersionOverride_diamond_differentCompatibilityLevels() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) |
| .buildOrThrow(); |
| ImmutableMap<String, ModuleOverride> overrides = |
| ImmutableMap.of( |
| "ddd", |
| MultipleVersionOverride.create( |
| ImmutableList.of(Version.parse("1.0"), Version.parse("2.0")), "")); |
| |
| Selection.Result selectionResult = Selection.run(depGraph, overrides); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "1.0", 1).buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0", 2).buildEntry()) |
| .inOrder(); |
| |
| assertThat(selectionResult.getUnprunedDepGraph()) |
| .isEqualTo(selectionResult.getResolvedDepGraph()); |
| } |
| |
| @Test |
| public void multipleVersionOverride_diamond_sameCompatibilityLevel() throws Exception { |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "1.0").buildEntry()) |
| .put(InterimModuleBuilder.create("ddd", "2.0").buildEntry()) |
| .buildOrThrow(); |
| ImmutableMap<String, ModuleOverride> overrides = |
| ImmutableMap.of( |
| "ddd", |
| MultipleVersionOverride.create( |
| ImmutableList.of(Version.parse("1.0"), Version.parse("2.0")), "")); |
| |
| Selection.Result selectionResult = Selection.run(depGraph, overrides); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb_from_aaa", createModuleKey("bbb", "1.0")) |
| .addDep("ccc_from_aaa", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb", "1.0") |
| .addDep("ddd_from_bbb", createModuleKey("ddd", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0") |
| .addDep("ddd_from_ccc", createModuleKey("ddd", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ddd", "1.0").buildEntry(), |
| InterimModuleBuilder.create("ddd", "2.0").buildEntry()) |
| .inOrder(); |
| |
| assertThat(selectionResult.getUnprunedDepGraph()) |
| .isEqualTo(selectionResult.getResolvedDepGraph()); |
| } |
| |
| @Test |
| public void multipleVersionOverride_diamond_snappingToNextHighestVersion() throws Exception { |
| // aaa --> bbb1@1.0 -> ccc@1.0 |
| // \-> bbb2@1.0 -> ccc@1.3 [allowed] |
| // \-> bbb3@1.0 -> ccc@1.5 |
| // \-> bbb4@1.0 -> ccc@1.7 [allowed] |
| // \-> bbb5@1.0 -> ccc@2.0 [allowed] |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb1", createModuleKey("bbb1", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb2", "1.0")) |
| .addDep("bbb3", createModuleKey("bbb3", "1.0")) |
| .addDep("bbb4", createModuleKey("bbb4", "1.0")) |
| .addDep("bbb5", createModuleKey("bbb5", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb1", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb2", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.3")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb3", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.5")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb4", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.7")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb5", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "1.3", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "1.5", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "1.7", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) |
| .buildOrThrow(); |
| ImmutableMap<String, ModuleOverride> overrides = |
| ImmutableMap.of( |
| "ccc", |
| MultipleVersionOverride.create( |
| ImmutableList.of(Version.parse("1.3"), Version.parse("1.7"), Version.parse("2.0")), |
| "")); |
| |
| // aaa --> bbb1@1.0 -> ccc@1.3 [originally ccc@1.0] |
| // \-> bbb2@1.0 -> ccc@1.3 [allowed] |
| // \-> bbb3@1.0 -> ccc@1.7 [originally ccc@1.5] |
| // \-> bbb4@1.0 -> ccc@1.7 [allowed] |
| // \-> bbb5@1.0 -> ccc@2.0 [allowed] |
| Selection.Result selectionResult = Selection.run(depGraph, overrides); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb1", createModuleKey("bbb1", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb2", "1.0")) |
| .addDep("bbb3", createModuleKey("bbb3", "1.0")) |
| .addDep("bbb4", createModuleKey("bbb4", "1.0")) |
| .addDep("bbb5", createModuleKey("bbb5", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb1", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.3")) |
| .addOriginalDep("ccc", createModuleKey("ccc", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb2", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.3")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb3", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.7")) |
| .addOriginalDep("ccc", createModuleKey("ccc", "1.5")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb4", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.7")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb5", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.3", 1).buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.7", 1).buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) |
| .inOrder(); |
| |
| assertThat(selectionResult.getUnprunedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb1", createModuleKey("bbb1", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb2", "1.0")) |
| .addDep("bbb3", createModuleKey("bbb3", "1.0")) |
| .addDep("bbb4", createModuleKey("bbb4", "1.0")) |
| .addDep("bbb5", createModuleKey("bbb5", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb1", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.3")) |
| .addOriginalDep("ccc", createModuleKey("ccc", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb2", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.3")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb3", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.7")) |
| .addOriginalDep("ccc", createModuleKey("ccc", "1.5")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb4", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.7")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb5", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.3", 1).buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.5", 1).buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.7", 1).buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()); |
| } |
| |
| @Test |
| public void multipleVersionOverride_diamond_dontSnapToDifferentCompatibility() throws Exception { |
| // aaa --> bbb1@1.0 -> ccc@1.0 [allowed] |
| // \-> bbb2@1.0 -> ccc@1.7 |
| // \-> bbb3@1.0 -> ccc@2.0 [allowed] |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb1", createModuleKey("bbb1", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb2", "1.0")) |
| .addDep("bbb3", createModuleKey("bbb3", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb1", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb2", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.7")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb3", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "1.7", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) |
| .buildOrThrow(); |
| ImmutableMap<String, ModuleOverride> overrides = |
| ImmutableMap.of( |
| "ccc", |
| MultipleVersionOverride.create( |
| ImmutableList.of(Version.parse("1.0"), Version.parse("2.0")), "")); |
| |
| ExternalDepsException e = |
| assertThrows(ExternalDepsException.class, () -> Selection.run(depGraph, overrides)); |
| assertThat(e) |
| .hasMessageThat() |
| .contains( |
| "bbb2@1.0 depends on ccc@1.7 which is not allowed by the multiple_version_override on" |
| + " ccc, which allows only [1.0, 2.0]"); |
| } |
| |
| @Test |
| public void multipleVersionOverride_diamond_unknownCompatibility() throws Exception { |
| // aaa --> bbb1@1.0 -> ccc@1.0 [allowed] |
| // \-> bbb2@1.0 -> ccc@2.0 [allowed] |
| // \-> bbb3@1.0 -> ccc@3.0 |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb1", createModuleKey("bbb1", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb2", "1.0")) |
| .addDep("bbb3", createModuleKey("bbb3", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb1", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb2", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb3", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "3.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "3.0", 3).buildEntry()) |
| .buildOrThrow(); |
| ImmutableMap<String, ModuleOverride> overrides = |
| ImmutableMap.of( |
| "ccc", |
| MultipleVersionOverride.create( |
| ImmutableList.of(Version.parse("1.0"), Version.parse("2.0")), "")); |
| |
| ExternalDepsException e = |
| assertThrows(ExternalDepsException.class, () -> Selection.run(depGraph, overrides)); |
| assertThat(e) |
| .hasMessageThat() |
| .contains( |
| "bbb3@1.0 depends on ccc@3.0 which is not allowed by the multiple_version_override on" |
| + " ccc, which allows only [1.0, 2.0]"); |
| } |
| |
| @Test |
| public void multipleVersionOverride_diamond_badVersionsAreOkayIfUnreferenced() throws Exception { |
| // aaa --> bbb1@1.0 --> ccc@1.0 [allowed] |
| // \ \-> bbb2@1.1 |
| // \-> bbb2@1.0 --> ccc@1.5 |
| // \-> bbb3@1.0 --> ccc@2.0 [allowed] |
| // \ \-> bbb4@1.1 |
| // \-> bbb4@1.0 --> ccc@3.0 |
| ImmutableMap<ModuleKey, InterimModule> depGraph = |
| ImmutableMap.<ModuleKey, InterimModule>builder() |
| .put( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb1", createModuleKey("bbb1", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb2", "1.0")) |
| .addDep("bbb3", createModuleKey("bbb3", "1.0")) |
| .addDep("bbb4", createModuleKey("bbb4", "1.0")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb1", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb2", "1.1")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb2", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.5")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("bbb2", "1.1").buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb3", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .addDep("bbb4", createModuleKey("bbb4", "1.1")) |
| .buildEntry()) |
| .put( |
| InterimModuleBuilder.create("bbb4", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "3.0")) |
| .buildEntry()) |
| .put(InterimModuleBuilder.create("bbb4", "1.1").buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "1.5", 1).buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) |
| .put(InterimModuleBuilder.create("ccc", "3.0", 3).buildEntry()) |
| .buildOrThrow(); |
| ImmutableMap<String, ModuleOverride> overrides = |
| ImmutableMap.of( |
| "ccc", |
| MultipleVersionOverride.create( |
| ImmutableList.of(Version.parse("1.0"), Version.parse("2.0")), "")); |
| |
| // aaa --> bbb1@1.0 --> ccc@1.0 [allowed] |
| // \ \-> bbb2@1.1 |
| // \-> bbb2@1.1 |
| // \-> bbb3@1.0 --> ccc@2.0 [allowed] |
| // \ \-> bbb4@1.1 |
| // \-> bbb4@1.1 |
| // ccc@1.5 and ccc@3.0, the versions violating the allowlist, are gone. |
| Selection.Result selectionResult = Selection.run(depGraph, overrides); |
| assertThat(selectionResult.getResolvedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb1", createModuleKey("bbb1", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb2", "1.1")) |
| .addOriginalDep("bbb2", createModuleKey("bbb2", "1.0")) |
| .addDep("bbb3", createModuleKey("bbb3", "1.0")) |
| .addDep("bbb4", createModuleKey("bbb4", "1.1")) |
| .addOriginalDep("bbb4", createModuleKey("bbb4", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb1", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb2", "1.1")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb2", "1.1").buildEntry(), |
| InterimModuleBuilder.create("bbb3", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .addDep("bbb4", createModuleKey("bbb4", "1.1")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb4", "1.1").buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry()) |
| .inOrder(); |
| |
| assertThat(selectionResult.getUnprunedDepGraph().entrySet()) |
| .containsExactly( |
| InterimModuleBuilder.create("aaa", Version.EMPTY) |
| .setKey(ModuleKey.ROOT) |
| .addDep("bbb1", createModuleKey("bbb1", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb2", "1.1")) |
| .addOriginalDep("bbb2", createModuleKey("bbb2", "1.0")) |
| .addDep("bbb3", createModuleKey("bbb3", "1.0")) |
| .addDep("bbb4", createModuleKey("bbb4", "1.1")) |
| .addOriginalDep("bbb4", createModuleKey("bbb4", "1.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb1", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.0")) |
| .addDep("bbb2", createModuleKey("bbb2", "1.1")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb2", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "1.5")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb2", "1.1").buildEntry(), |
| InterimModuleBuilder.create("bbb3", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "2.0")) |
| .addDep("bbb4", createModuleKey("bbb4", "1.1")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb4", "1.0") |
| .addDep("ccc", createModuleKey("ccc", "3.0")) |
| .buildEntry(), |
| InterimModuleBuilder.create("bbb4", "1.1").buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.0", 1).buildEntry(), |
| InterimModuleBuilder.create("ccc", "1.5", 1).buildEntry(), |
| InterimModuleBuilder.create("ccc", "2.0", 2).buildEntry(), |
| InterimModuleBuilder.create("ccc", "3.0", 3).buildEntry()); |
| } |
| } |