interaction_env_handler.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // Copyright 2019 The etcd 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. package rafttest
  15. import (
  16. "fmt"
  17. "strconv"
  18. "testing"
  19. "github.com/cockroachdb/datadriven"
  20. )
  21. // Handle is the entrypoint for data-driven interaction testing. Commands and
  22. // parameters are parsed from the supplied TestData. Errors during data parsing
  23. // are reported via the supplied *testing.T; errors from the raft nodes and the
  24. // storage engine are reported to the output buffer.
  25. func (env *InteractionEnv) Handle(t *testing.T, d datadriven.TestData) string {
  26. env.Output.Reset()
  27. var err error
  28. switch d.Cmd {
  29. case "add-nodes":
  30. // Example:
  31. //
  32. // add-nodes <number-of-nodes-to-add> voters=(1 2 3) learners=(4 5) index=2 content=foo
  33. err = env.handleAddNodes(t, d)
  34. case "campaign":
  35. // Example:
  36. //
  37. // campaign <id-of-candidate>
  38. err = env.handleCampaign(t, d)
  39. case "compact":
  40. // Example:
  41. //
  42. // compact <id> <new-first-index>
  43. err = env.handleCompact(t, d)
  44. case "deliver-msgs":
  45. // Deliver the messages for a given recipient.
  46. //
  47. // Example:
  48. //
  49. // deliver-msgs <idx>
  50. err = env.handleDeliverMsgs(t, d)
  51. case "process-ready":
  52. // Example:
  53. //
  54. // process-ready 3
  55. err = env.handleProcessReady(t, d)
  56. case "log-level":
  57. // Set the log level. NONE disables all output, including from the test
  58. // harness (except errors).
  59. //
  60. // Example:
  61. //
  62. // log-level WARN
  63. err = env.handleLogLevel(t, d)
  64. case "raft-log":
  65. // Print the Raft log.
  66. //
  67. // Example:
  68. //
  69. // raft-log 3
  70. err = env.handleRaftLog(t, d)
  71. case "stabilize":
  72. // Deliver messages to and run process-ready on the set of IDs until
  73. // no more work is to be done.
  74. //
  75. // Example:
  76. //
  77. // stabilize 1 4
  78. err = env.handleStabilize(t, d)
  79. case "status":
  80. // Print Raft status.
  81. //
  82. // Example:
  83. //
  84. // status 5
  85. err = env.handleStatus(t, d)
  86. case "tick-heartbeat":
  87. // Tick a heartbeat interval.
  88. //
  89. // Example:
  90. //
  91. // tick-heartbeat 3
  92. err = env.handleTickHeartbeat(t, d)
  93. case "propose-conf-change":
  94. // Propose a configuration change.
  95. //
  96. // Example:
  97. //
  98. // propose-conf-change transition=explicit
  99. // v1 v3 l4 r5
  100. //
  101. // Example:
  102. //
  103. // propose-conf-change v1=true
  104. // v5
  105. err = env.handleProposeConfChange(t, d)
  106. default:
  107. err = fmt.Errorf("unknown command")
  108. }
  109. if err != nil {
  110. env.Output.WriteString(err.Error())
  111. }
  112. // NB: the highest log level suppresses all output, including that of the
  113. // handlers. This comes in useful during setup which can be chatty.
  114. // However, errors are always logged.
  115. if env.Output.Len() == 0 {
  116. return "ok"
  117. }
  118. if env.Output.Lvl == len(lvlNames)-1 {
  119. if err != nil {
  120. return err.Error()
  121. }
  122. return "ok (quiet)"
  123. }
  124. return env.Output.String()
  125. }
  126. func firstAsInt(t *testing.T, d datadriven.TestData) int {
  127. t.Helper()
  128. n, err := strconv.Atoi(d.CmdArgs[0].Key)
  129. if err != nil {
  130. t.Fatal(err)
  131. }
  132. return n
  133. }
  134. func firstAsNodeIdx(t *testing.T, d datadriven.TestData) int {
  135. t.Helper()
  136. n := firstAsInt(t, d)
  137. return n - 1
  138. }
  139. func ints(t *testing.T, d datadriven.TestData) []int {
  140. var ints []int
  141. for i := 0; i < len(d.CmdArgs); i++ {
  142. if len(d.CmdArgs[i].Vals) != 0 {
  143. continue
  144. }
  145. n, err := strconv.Atoi(d.CmdArgs[i].Key)
  146. if err != nil {
  147. t.Fatal(err)
  148. }
  149. ints = append(ints, n)
  150. }
  151. return ints
  152. }