blob: 4a5da7be2f3cc63a0a5f6a1ce900c0464c62677b [file] [log] [blame]
// Copyright 2023 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.util;
import static com.google.common.truth.Truth.assertThat;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit test for {@link LatestObjectMetricExporter}. */
@RunWith(JUnit4.class)
public class LatestObjectMetricExporterTest {
@Test
public void weakReferencesAreGarbageCollected() {
// Create an exporter with the given strength and whose registration stores the Supplier<Object>
// in an AtomicReference.
LatestObjectMetricExporter.Strength strength = LatestObjectMetricExporter.Strength.WEAK;
AtomicReference<Supplier<Object>> registeredSupplierRef = new AtomicReference<>(null);
LatestObjectMetricExporter.CallbackRegistration<Object> registration =
registeredSupplierRef::set;
LatestObjectMetricExporter<Object> exporter =
new LatestObjectMetricExporter<>(strength, registration);
assertThat(registeredSupplierRef.get()).isNull();
// Set up three Objects to serve as dummy "latest objects" to pass through the exporter.
Object first = new Object();
Object second = new Object();
Object third = new Object();
// Set the first value, at which point the registration will run and we will get the Supplier
// that tells us the currently exported object.
exporter.setLatestInstance(first);
Supplier<Object> latestObjectSupplier = registeredSupplierRef.get();
assertThat(latestObjectSupplier).isNotNull();
assertThat(latestObjectSupplier.get()).isSameInstanceAs(first);
// Remove only reference to the latest object and run the GC. The supplier should start
// producing null, not `first`.
first = null;
Runtime runtime = Runtime.getRuntime();
runtime.gc();
assertThat(latestObjectSupplier.get()).isNull();
// Remove only reference to the latest object but don't run the GC. The supplier should still
// return `second` until we change the latest inatance to `third`, at which point GC has no
// observable effect..
exporter.setLatestInstance(second);
assertThat(latestObjectSupplier.get()).isSameInstanceAs(second);
second = null;
exporter.setLatestInstance(third);
assertThat(latestObjectSupplier.get()).isSameInstanceAs(third);
runtime.gc();
assertThat(latestObjectSupplier.get()).isSameInstanceAs(third);
// Repeat the first assertion: removing the reference and GCing will cause the Supplier
// to produce null, not `third`.
third = null;
runtime.gc();
assertThat(latestObjectSupplier.get()).isNull();
}
}