Coverage Report

Created: 2026-08-14 07:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/connectedhomeip/third_party/fuzztest/common/bazel.cc
Line
Count
Source
1
// Copyright 2024 The Centipede Authors.
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
//      https://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.
14
15
#include "./common/bazel.h"
16
17
#include <algorithm>
18
#include <cstdlib>
19
#include <string>
20
21
#include "absl/log/check.h"
22
#include "absl/status/status.h"
23
#include "absl/strings/numbers.h"
24
#include "absl/strings/str_cat.h"
25
#include "absl/time/clock.h"
26
#include "absl/time/time.h"
27
28
namespace centipede {
29
30
namespace {
31
32
0
absl::Duration GetBazelTestTimeout() {
33
0
  const char *test_timeout_env = std::getenv("TEST_TIMEOUT");
34
0
  if (test_timeout_env == nullptr) return absl::InfiniteDuration();
35
  // When using `bazel run`, `TEST_TIMEOUT` is set but not used, and we should
36
  // ignore the timeout. We detect this by the presence of
37
  // `BUILD_WORKSPACE_DIRECTORY`
38
  // (https://bazel.build/docs/user-manual#running-executables).
39
0
  if (std::getenv("BUILD_WORKSPACE_DIRECTORY") != nullptr) {
40
0
    return absl::InfiniteDuration();
41
0
  }
42
0
  int timeout_s = 0;
43
0
  CHECK(absl::SimpleAtoi(test_timeout_env, &timeout_s))
44
0
      << "Failed to parse TEST_TIMEOUT: \"" << test_timeout_env << "\"";
45
0
  return absl::Seconds(timeout_s);
46
0
}
47
48
}  // namespace
49
50
0
TestShard GetBazelTestShard() {
51
0
  static TestShard cached_test_shard = [] {
52
0
    TestShard test_shard;
53
0
    if (const char *test_total_shards_env = std::getenv("TEST_TOTAL_SHARDS");
54
0
        test_total_shards_env != nullptr) {
55
0
      CHECK(absl::SimpleAtoi(test_total_shards_env, &test_shard.total_shards))
56
0
          << "Failed to parse TEST_TOTAL_SHARDS as an integer: \""
57
0
          << test_total_shards_env << "\"";
58
0
      CHECK_GT(test_shard.total_shards, 0)
59
0
          << "TEST_TOTAL_SHARDS must be greater than 0.";
60
0
    }
61
0
    if (const char *test_shard_index_env = std::getenv("TEST_SHARD_INDEX");
62
0
        test_shard_index_env != nullptr) {
63
0
      CHECK(absl::SimpleAtoi(test_shard_index_env, &test_shard.index))
64
0
          << "Failed to parse TEST_SHARD_INDEX as an integer: \""
65
0
          << test_shard_index_env << "\"";
66
0
      CHECK(0 <= test_shard.index && test_shard.index < test_shard.total_shards)
67
0
          << "TEST_SHARD_INDEX must be in the range [0, "
68
0
          << test_shard.total_shards << ").";
69
0
    }
70
0
    return test_shard;
71
0
  }();
72
0
  return cached_test_shard;
73
0
}
74
75
absl::Status VerifyBazelHasEnoughTimeToRunTest(absl::Time target_start_time,
76
                                               absl::Duration test_time_limit,
77
                                               int executed_tests_in_shard,
78
0
                                               int fuzz_test_count) {
79
0
  static const absl::Duration bazel_test_timeout = GetBazelTestTimeout();
80
0
  const int shard_count = GetBazelTestShard().total_shards;
81
0
  constexpr float kTimeoutSafetyFactor = 1.2;
82
0
  const auto required_test_time = kTimeoutSafetyFactor * test_time_limit;
83
0
  const auto remaining_duration =
84
0
      bazel_test_timeout - (absl::Now() - target_start_time);
85
0
  if (required_test_time <= remaining_duration) return absl::OkStatus();
86
0
  std::string error =
87
0
      "Cannot fuzz a fuzz test within the given timeout. Please ";
88
0
  if (executed_tests_in_shard == 0) {
89
    // Increasing number of shards won't help.
90
0
    const absl::Duration suggested_timeout =
91
0
        required_test_time * ((fuzz_test_count - 1) / shard_count + 1);
92
0
    absl::StrAppend(&error, "set the `timeout` to ", suggested_timeout,
93
0
                    " or reduce the fuzzing time, ");
94
0
  } else {
95
0
    constexpr int kMaxShardCount = 50;
96
0
    const int suggested_shard_count = std::min(
97
0
        (fuzz_test_count - 1) / executed_tests_in_shard + 1, kMaxShardCount);
98
0
    const int suggested_tests_per_shard =
99
0
        (fuzz_test_count - 1) / suggested_shard_count + 1;
100
0
    if (suggested_tests_per_shard > executed_tests_in_shard) {
101
      // We wouldn't be able to execute the suggested number of tests without
102
      // timeout. This case can only happen if we would in fact need more than
103
      // `kMaxShardCount` shards, indicating that there are simply too many fuzz
104
      // tests in a binary.
105
0
      CHECK_EQ(suggested_shard_count, kMaxShardCount);
106
0
      absl::StrAppend(&error,
107
0
                      "split the fuzz tests into several test binaries where "
108
0
                      "each binary has at most ",
109
0
                      executed_tests_in_shard * kMaxShardCount, "tests ",
110
0
                      "with `shard_count` = ", kMaxShardCount, ", ");
111
0
    } else {
112
      // In this case, `suggested_shard_count` must be greater than
113
      // `shard_count`, otherwise we would have already executed all the tests
114
      // without a timeout.
115
0
      CHECK_GT(suggested_shard_count, shard_count);
116
0
      absl::StrAppend(&error, "increase the `shard_count` to ",
117
0
                      suggested_shard_count, ", ");
118
0
    }
119
0
  }
120
0
  absl::StrAppend(&error, "to avoid this issue. ");
121
0
  absl::StrAppend(&error,
122
0
                  "(https://bazel.build/reference/be/"
123
0
                  "common-definitions#common-attributes-tests)");
124
0
  return absl::ResourceExhaustedError(error);
125
0
}
126
127
}  // namespace centipede