| // Copyright 2022 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.skyframe; | |
| import static com.google.common.truth.Truth.assertThat; | |
| import static org.mockito.Mockito.mock; | |
| import static org.mockito.Mockito.verify; | |
| import static org.mockito.Mockito.verifyNoMoreInteractions; | |
| import static org.mockito.Mockito.when; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.common.collect.ImmutableMap; | |
| import com.google.common.collect.ImmutableSet; | |
| import com.google.devtools.build.lib.bugreport.BugReporter; | |
| import org.junit.Test; | |
| import org.junit.runner.RunWith; | |
| import org.junit.runners.JUnit4; | |
| /** Tests for {@link GraphTraversingHelper}. */ | |
| @RunWith(JUnit4.class) | |
| public final class GraphTraversingHelperTest { | |
| private final SkyFunction.Environment mockEnv = mock(SkyFunction.Environment.class); | |
| private final SkyKey keyA = mock(SkyKey.class, "keyA"); | |
| private final SkyKey keyB = mock(SkyKey.class, "keyB"); | |
| private final SomeErrorException exn = new SomeErrorException(""); | |
| private final SkyValue value = mock(SkyValue.class); | |
| private static final class SomeOtherErrorException extends Exception { | |
| private SomeOtherErrorException() {} | |
| } | |
| @Test | |
| public void declareDependenciesAndCheckIfValuesMissing_valuesMissingBeforeCompute() | |
| throws Exception { | |
| when(mockEnv.valuesMissing()).thenReturn(true); | |
| when(mockEnv.getValuesAndExceptions(ImmutableSet.of(keyA))).thenReturn(null); | |
| boolean valuesMissing = | |
| GraphTraversingHelper.declareDependenciesAndCheckIfValuesMissing( | |
| mockEnv, ImmutableSet.of(keyA), SomeOtherErrorException.class); | |
| assertThat(valuesMissing).isTrue(); | |
| } | |
| @Test | |
| public void declareDependenciesAndCheckIfValuesMissing_valuesMissingAfterCompute() | |
| throws Exception { | |
| BugReporter mockReporter = mock(BugReporter.class); | |
| SkyframeLookupResult result = | |
| new SimpleSkyframeLookupResult( | |
| () -> {}, ImmutableMap.of(keyA, ValueOrUntypedException.ofExn(exn))::get); | |
| when(mockEnv.getValuesAndExceptions(ImmutableSet.of(keyA))).thenReturn(result); | |
| boolean valuesMissing = | |
| GraphTraversingHelper.declareDependenciesAndCheckIfValuesMissing( | |
| mockEnv, | |
| ImmutableSet.of(keyA), | |
| SomeOtherErrorException.class, | |
| /*exceptionClass2=*/ null, | |
| mockReporter); | |
| verify(mockReporter) | |
| .logUnexpected("Value for: '%s' was missing, this should never happen", keyA); | |
| verifyNoMoreInteractions(mockReporter); | |
| assertThat(valuesMissing).isTrue(); | |
| } | |
| @Test | |
| public void declareDependenciesAndCheckIfValuesMissing_notValuesMissingAfterCompute() | |
| throws Exception { | |
| SkyframeLookupResult result = | |
| new SimpleSkyframeLookupResult( | |
| () -> {}, | |
| ImmutableMap.of( | |
| keyA, | |
| ValueOrUntypedException.ofExn(exn), | |
| keyB, | |
| ValueOrUntypedException.ofValueUntyped(value)) | |
| ::get); | |
| when(mockEnv.getValuesAndExceptions(ImmutableList.of(keyA, keyB))).thenReturn(result); | |
| boolean valuesMissing = | |
| GraphTraversingHelper.declareDependenciesAndCheckIfValuesMissing( | |
| mockEnv, ImmutableList.of(keyA, keyB), SomeErrorException.class); | |
| assertThat(valuesMissing).isFalse(); | |
| } | |
| @Test | |
| public void declareDependenciesAndCheckIfValuesMissing_nullAfterError_hasCorrectKeyInBugReport() | |
| throws Exception { | |
| SkyframeLookupResult result = | |
| new SimpleSkyframeLookupResult( | |
| () -> {}, | |
| ImmutableMap.of( | |
| keyA, | |
| ValueOrUntypedException.ofExn(exn), | |
| keyB, | |
| ValueOrUntypedException.ofNull()) | |
| ::get); | |
| when(mockEnv.getValuesAndExceptions(ImmutableList.of(keyA, keyB))).thenReturn(result); | |
| BugReporter mockReporter = mock(BugReporter.class); | |
| boolean valuesMissing = | |
| GraphTraversingHelper.declareDependenciesAndCheckIfValuesMissing( | |
| mockEnv, ImmutableList.of(keyA, keyB), SomeErrorException.class, null, mockReporter); | |
| assertThat(valuesMissing).isTrue(); | |
| verify(mockReporter) | |
| .logUnexpected("Value for: '%s' was missing, this should never happen", keyB); | |
| verifyNoMoreInteractions(mockReporter); | |
| } | |
| @Test | |
| public void declareDependenciesAndCheckIfValuesMissingMaybeWithExceptions_beforeCompute() | |
| throws Exception { | |
| when(mockEnv.valuesMissing()).thenReturn(true); | |
| when(mockEnv.getValuesAndExceptions(ImmutableSet.of(keyB))).thenReturn(null); | |
| assertThat( | |
| GraphTraversingHelper.declareDependenciesAndCheckIfValuesMissingMaybeWithExceptions( | |
| mockEnv, ImmutableSet.of(keyB))) | |
| .isTrue(); | |
| } | |
| @Test | |
| public void declareDependenciesAndCheckIfValuesMissingMaybeWithExceptions_valuesMissing() | |
| throws Exception { | |
| when(mockEnv.getValuesAndExceptions(ImmutableSet.of(keyA))) | |
| .thenReturn( | |
| new SimpleSkyframeLookupResult( | |
| () -> {}, ImmutableMap.of(keyA, ValueOrUntypedException.ofExn(exn))::get)); | |
| assertThat( | |
| GraphTraversingHelper.declareDependenciesAndCheckIfValuesMissingMaybeWithExceptions( | |
| mockEnv, ImmutableSet.of(keyA))) | |
| .isTrue(); | |
| } | |
| @Test | |
| public void declareDependenciesAndCheckIfValuesMissingMaybeWithExceptions_notValuesMissing() | |
| throws Exception { | |
| when(mockEnv.getValuesAndExceptions(ImmutableSet.of(keyB))) | |
| .thenReturn( | |
| new SimpleSkyframeLookupResult( | |
| () -> {}, | |
| ImmutableMap.of(keyB, ValueOrUntypedException.ofValueUntyped(value))::get)); | |
| assertThat( | |
| GraphTraversingHelper.declareDependenciesAndCheckIfValuesMissingMaybeWithExceptions( | |
| mockEnv, ImmutableSet.of(keyB))) | |
| .isFalse(); | |
| } | |
| } |