mzcompose.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. # Copyright Materialize, Inc. and contributors. All rights reserved.
  2. #
  3. # Use of this software is governed by the Business Source License
  4. # included in the LICENSE file at the root of this repository.
  5. #
  6. # As of the Change Date specified in that file, in accordance with
  7. # the Business Source License, use of this software will be governed
  8. # by the Apache License, Version 2.0.
  9. """
  10. Run SQLancer against Materialize: Automated testing to find logic bugs in
  11. database systems: https://github.com/sqlancer/sqlancer
  12. """
  13. import argparse
  14. import random
  15. from threading import Thread
  16. from materialize import spawn
  17. from materialize.mzcompose.composition import (
  18. Composition,
  19. Service,
  20. WorkflowArgumentParser,
  21. )
  22. from materialize.mzcompose.services.materialized import Materialized
  23. SERVICES = [
  24. # Auto-restart so we can keep testing even after we ran into a panic
  25. Materialized(restart="on-failure", default_replication_factor=2),
  26. Service(
  27. "sqlancer",
  28. {
  29. "mzbuild": "sqlancer",
  30. },
  31. ),
  32. ]
  33. def print_logs(container_id: str) -> None:
  34. spawn.runv(["docker", "logs", "-f", container_id])
  35. def workflow_default(c: Composition, parser: WorkflowArgumentParser) -> None:
  36. parser.add_argument("--runtime", default=600, type=int)
  37. parser.add_argument("--num-tries", default=100000, type=int)
  38. parser.add_argument("--num-threads", default=4, type=int)
  39. parser.add_argument("--seed", default=None, type=int)
  40. parser.add_argument("--qpg", default=True, action=argparse.BooleanOptionalAction)
  41. parser.add_argument("--oracle", default="NOREC", type=str)
  42. args = parser.parse_args()
  43. c.up("materialized")
  44. c.sql(
  45. "ALTER SYSTEM SET max_tables TO 1000",
  46. user="mz_system",
  47. port=6877,
  48. )
  49. c.sql(
  50. "ALTER SYSTEM SET max_materialized_views TO 1000",
  51. user="mz_system",
  52. port=6877,
  53. )
  54. seed = args.seed or random.randint(0, 2**31)
  55. print("--- Run in progress")
  56. result = c.run(
  57. "sqlancer",
  58. "--random-seed",
  59. f"{seed}",
  60. "--host",
  61. "materialized",
  62. "--port",
  63. "6875",
  64. "--username",
  65. "materialize",
  66. "--timeout-seconds",
  67. f"{args.runtime}",
  68. "--num-tries",
  69. f"{args.num_tries}",
  70. "--num-threads",
  71. f"{args.num_threads}",
  72. "--qpg-enable",
  73. f"{args.qpg}",
  74. "--random-string-generation",
  75. "ALPHANUMERIC_SPECIALCHAR",
  76. "materialize",
  77. "--oracle",
  78. args.oracle,
  79. check=False,
  80. detach=True,
  81. capture=True,
  82. )
  83. container_id = result.stdout.strip()
  84. # Print logs in a background thread so that we get immediate output in CI,
  85. # and also when running SQLancer locally
  86. thread = Thread(target=print_logs, args=(container_id,))
  87. thread.start()
  88. # At the same time capture the logs to analyze for finding new issues
  89. stdout = spawn.capture(["docker", "logs", "-f", container_id])
  90. in_assertion = False
  91. for line in stdout.splitlines():
  92. if line.startswith("--java.lang.AssertionError: "):
  93. in_assertion = True
  94. print(f"--- [SQLancer] {line.removeprefix('--java.lang.AssertionError: ')}")
  95. elif line == "":
  96. in_assertion = False
  97. elif in_assertion:
  98. print(line)
  99. print(f"--- {result.stdout.splitlines()[-1]}")