1# Copyright 2021 gRPC 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#     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.
14"""This contains common helpers for generating randomized data."""
15import random
16import string
17
18import framework.helpers.datetime
19
20# Alphanumeric characters, similar to regex [:alnum:] class, [a-zA-Z0-9]
21ALPHANUM = string.ascii_letters + string.digits
22# Lowercase alphanumeric characters: [a-z0-9]
23# Use ALPHANUM_LOWERCASE alphabet when case-sensitivity is a concern.
24ALPHANUM_LOWERCASE = string.ascii_lowercase + string.digits
25
26
27def rand_string(length: int = 8, *, lowercase: bool = False) -> str:
28    """Return random alphanumeric string of given length.
29
30   Space for default arguments: alphabet^length
31      lowercase and uppercase = (26*2 + 10)^8 = 2.18e14 = 218 trillion.
32      lowercase only = (26 + 10)^8 = 2.8e12 = 2.8 trillion.
33   """
34    alphabet = ALPHANUM_LOWERCASE if lowercase else ALPHANUM
35    return ''.join(random.choices(population=alphabet, k=length))
36
37
38def random_resource_suffix() -> str:
39    """Return a ready-to-use resource suffix with datetime and nonce."""
40    # Date and time suffix for debugging. Seconds skipped, not as relevant
41    # Format example: 20210626-1859
42    datetime_suffix: str = framework.helpers.datetime.datetime_suffix()
43    # Use lowercase chars because some resource names won't allow uppercase.
44    # For len 5, total (26 + 10)^5 = 60,466,176 combinations.
45    # Approx. number of test runs needed to start at the same minute to
46    # produce a collision: math.sqrt(math.pi/2 * (26+10)**5) ≈ 9745.
47    # https://en.wikipedia.org/wiki/Birthday_attack#Mathematics
48    unique_hash: str = rand_string(5, lowercase=True)
49    return f'{datetime_suffix}-{unique_hash}'
50