...

Source file src/go.etcd.io/etcd/raft/v3/rafttest/interaction_env_handler.go

Documentation: go.etcd.io/etcd/raft/v3/rafttest

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

View as plain text