blob: 5690fecaf559ca3a72f2c3c892bf66b85533dbb6 [file] [log] [blame]
shahan0eddd292018-06-05 18:12:03 -07001// Copyright 2018 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.actions;
15
16import static com.google.common.truth.Truth.assertThat;
17import static java.nio.charset.StandardCharsets.US_ASCII;
18
19import com.google.devtools.build.lib.actions.cache.Metadata;
20import com.google.devtools.build.lib.vfs.PathFragment;
21import java.util.ArrayList;
22import java.util.Collections;
23import java.util.HashSet;
24import java.util.Random;
25import org.junit.Before;
26import org.junit.Test;
27import org.junit.runner.RunWith;
28import org.junit.runners.JUnit4;
29
30/** Unit test for {@link ActionInputMap}. */
31@RunWith(JUnit4.class)
32public final class ActionInputMapTest {
33
34 private ActionInputMap map;
35
36 @Before
37 public void init() {
38 map = new ActionInputMap(1); // small hint to stress the map
39 }
40
41 @Test
42 public void basicPutAndLookup() {
43 assertThat(put("/abc/def", 5)).isTrue();
44 assertThat(map.size()).isEqualTo(1);
45 assertContains("/abc/def", 5);
46 assertThat(map.getMetadata("blah")).isNull();
47 assertThat(map.getInput("blah")).isNull();
48 }
49
50 @Test
51 public void ignoresSubsequent() {
52 assertThat(put("/abc/def", 5)).isTrue();
53 assertThat(map.size()).isEqualTo(1);
54 assertThat(put("/abc/def", 6)).isFalse();
55 assertThat(map.size()).isEqualTo(1);
56 assertThat(put("/ghi/jkl", 7)).isTrue();
57 assertThat(map.size()).isEqualTo(2);
58 assertThat(put("/ghi/jkl", 8)).isFalse();
59 assertThat(map.size()).isEqualTo(2);
60 assertContains("/abc/def", 5);
61 assertContains("/ghi/jkl", 7);
62 }
63
64 @Test
65 public void clear() {
66 assertThat(put("/abc/def", 5)).isTrue();
67 assertThat(map.size()).isEqualTo(1);
68 assertThat(put("/ghi/jkl", 7)).isTrue();
69 assertThat(map.size()).isEqualTo(2);
70 map.clear();
71 assertThat(map.size()).isEqualTo(0);
72 assertThat(map.getMetadata("/abc/def")).isNull();
73 assertThat(map.getMetadata("/ghi/jkl")).isNull();
74 }
75
76 @Test
77 public void stress() {
78 ArrayList<TestEntry> data = new ArrayList<>();
79 {
80 Random rng = new Random();
81 HashSet<TestInput> deduper = new HashSet<>();
82 for (int i = 0; i < 100000; ++i) {
83 byte[] bytes = new byte[80];
84 rng.nextBytes(bytes);
85 for (int j = 0; j < bytes.length; ++j) {
86 bytes[j] &= ((byte) 0x7f);
87 }
88 TestInput nextInput = new TestInput(new String(bytes, US_ASCII));
89 if (deduper.add(nextInput)) {
90 data.add(new TestEntry(nextInput, new TestMetadata(i)));
91 }
92 }
93 }
94 for (int iteration = 0; iteration < 20; ++iteration) {
95 map.clear();
96 Collections.shuffle(data);
97 for (int i = 0; i < data.size(); ++i) {
98 TestEntry entry = data.get(i);
99 assertThat(map.put(entry.input, entry.metadata)).isTrue();
100 }
101 assertThat(map.size()).isEqualTo(data.size());
102 for (int i = 0; i < data.size(); ++i) {
103 TestEntry entry = data.get(i);
104 assertThat(map.getMetadata(entry.input)).isEqualTo(entry.metadata);
105 }
106 }
107 }
108
109 private boolean put(String execPath, int value) {
110 return map.put(new TestInput(execPath), new TestMetadata(value));
111 }
112
113 private void assertContains(String execPath, int value) {
114 assertThat(map.getMetadata(new TestInput(execPath))).isEqualTo(new TestMetadata(value));
115 assertThat(map.getMetadata(execPath)).isEqualTo(new TestMetadata(value));
116 assertThat(map.getInput(execPath)).isEqualTo(new TestInput(execPath));
117 }
118
119 private static class TestEntry {
120 public final TestInput input;
121 public final TestMetadata metadata;
122
123 public TestEntry(TestInput input, TestMetadata metadata) {
124 this.input = input;
125 this.metadata = metadata;
126 }
127 }
128
129 private static class TestInput implements ActionInput {
130 private final PathFragment fragment;
131
132 public TestInput(String fragment) {
133 this.fragment = PathFragment.create(fragment);
134 }
135
136 @Override
137 public PathFragment getExecPath() {
138 return fragment;
139 }
140
141 @Override
142 public String getExecPathString() {
143 return fragment.toString();
144 }
145
146 @Override
147 public boolean equals(Object other) {
148 if (!(other instanceof TestInput)) {
149 return false;
150 }
151 if (this == other) {
152 return true;
153 }
154 return fragment.equals(((TestInput) other).fragment);
155 }
156
157 @Override
158 public int hashCode() {
159 return fragment.hashCode();
160 }
161 }
162
163 private static class TestMetadata implements Metadata {
164 private final int id;
165
166 public TestMetadata(int id) {
167 this.id = id;
168 }
169
170 @Override
171 public FileStateType getType() {
172 throw new UnsupportedOperationException();
173 }
174
175 @Override
176 public byte[] getDigest() {
177 throw new UnsupportedOperationException();
178 }
179
180 @Override
181 public long getSize() {
182 throw new UnsupportedOperationException();
183 }
184
185 @Override
186 public long getModifiedTime() {
187 throw new UnsupportedOperationException();
188 }
189
190 @Override
191 @SuppressWarnings("EqualsHashCode")
192 public boolean equals(Object o) {
193 if (!(o instanceof TestMetadata)) {
194 return false;
195 }
196 return id == ((TestMetadata) o).id;
197 }
198 }
199}