aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/lib/collect/nestedset/DigestMapTest.java
blob: 67d9b8600915dd23a89c0ad2e10057496744ed84 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2018 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.collect.nestedset;

import static com.google.common.truth.Truth.assertThat;

import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.vfs.DigestHashFunction;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;

/** Tests for {@link DigestMap}. */
@RunWith(Parameterized.class)
public class DigestMapTest {

  @Parameters(name = "Hash: {0}")
  public static Iterable<Object[]> hashFunction() {
    return ImmutableList.of(
        new Object[] {DigestHashFunction.MD5}, new Object[] {DigestHashFunction.SHA256});
  }

  @Parameter public DigestHashFunction digestHashFunction;

  private Fingerprint fingerprint() {
    return new Fingerprint(digestHashFunction);
  }

  @Test
  public void simpleTest() {
    int count = 128; // Must be smaller than byte for this test or we'll overflow
    Object[] keys = new Object[count];
    for (int i = 0; i < count; ++i) {
      keys[i] = new Object();
    }

    DigestMap digestMap = new DigestMap(digestHashFunction, 4);
    for (int i = 0; i < count; ++i) {
      Fingerprint digest = fingerprint().addInt(i);
      Fingerprint fingerprint = fingerprint();
      digestMap.insertAndReadDigest(keys[i], digest, fingerprint);
      Fingerprint reference = fingerprint().addBytes(fingerprint().addInt(i).digestAndReset());
      assertThat(fingerprint.hexDigestAndReset()).isEqualTo(reference.hexDigestAndReset());
    }
    for (int i = 0; i < count; ++i) {
      Fingerprint fingerprint = fingerprint();
      assertThat(digestMap.readDigest(keys[i], fingerprint)).isTrue();
      Fingerprint reference = fingerprint().addBytes(fingerprint().addInt(i).digestAndReset());
      assertThat(fingerprint.hexDigestAndReset()).isEqualTo(reference.hexDigestAndReset());
    }
  }

  @Test
  public void concurrencyTest() throws Exception {
    int count = 128; // Must be smaller than byte for this test or we'll overflow
    Object[] keys = new Object[count];
    for (int i = 0; i < count; ++i) {
      keys[i] = new Object();
    }
    DigestMap digestMap = new DigestMap(digestHashFunction, 4);

    AtomicBoolean done = new AtomicBoolean();
    AtomicReference<Exception> exception = new AtomicReference<>();
    List<Thread> threads = new ArrayList<>();
    int threadCount = 16;
    for (int i = 0; i < threadCount; ++i) {
      Thread thread =
          new Thread(
              () -> {
                Random random = new Random();
                while (!done.get()) {
                  int index = random.nextInt(count);
                  Object key = keys[index];
                  Fingerprint fingerprint = fingerprint();
                  if (!digestMap.readDigest(key, fingerprint)) {
                    Fingerprint digest = fingerprint().addInt(index);
                    digestMap.insertAndReadDigest(key, digest, fingerprint);
                  }
                  Fingerprint reference =
                      fingerprint().addBytes(fingerprint().addInt(index).digestAndReset());
                  String hexDigest = fingerprint.hexDigestAndReset();
                  String referenceDigest = reference.hexDigestAndReset();
                  if (!hexDigest.equals(referenceDigest)) {
                    exception.set(
                        new IllegalStateException(
                            String.format(
                                "Digests are not equal: %s != %s, index %d",
                                hexDigest, referenceDigest, index)));
                    done.set(true);
                  }
                }
              });
      thread.start();
      threads.add(thread);
    }
    Thread.sleep(1000);
    done.set(true);
    for (int i = 0; i < threadCount; ++i) {
      threads.get(i).join(1000);
    }
    if (exception.get() != null) {
      throw exception.get();
    }
  }
}