Example #1
0
func Fuzz(data []byte) int {
	defer func() {
		if r := recover(); r != nil {
			if !panicExpected(r) {
				panic(r)
			}
		}
	}()

	// Run in insecure mode to avoid dealing with TLS.
	ctx := server.MakeTestContext()
	ctx.Insecure = true

	s := server.StartTestServerWithContext(nil, &ctx)
	defer s.Stop()

	conn, err := net.Dial("tcp", s.ServingAddr())
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	// Connect to the PGWire v3 server. This connection message includes information
	// to match with pgwire.Match and bypass sql/pgwire.parseOptions:
	// - 4 byte prefix for the buffer's length
	// - 4 bytes for the version30 value
	// - 1 byte for a null terminator to skip session args
	const version30 = 196608
	var connectBuf [9]byte
	binary.BigEndian.PutUint32(connectBuf[:4], uint32(len(connectBuf)))
	binary.BigEndian.PutUint32(connectBuf[4:8], version30)
	if err != nil {
		panic(err)
	}
	conn.Write(connectBuf[:])
	time.Sleep(1 * time.Millisecond)

	// Send a pgwire "typed message" (see sql/pgwire.readBuffer.{readTypedMsg, readUntypedMsg}).
	// The message includes:
	// - 1 byte for the type
	// - 4 bytes for the message's length (minus the type prefix)
	// - the rest of message
	//
	// TODO(nvanbenschoten) investigate sending multiple messages.
	sendBuf := data
	if len(data) > 1 {
		newLen := len(data) + 4
		sendBuf = make([]byte, newLen)
		sendBuf[0] = data[0]
		binary.BigEndian.PutUint32(sendBuf[1:5], uint32(newLen-1))
		copy(sendBuf[5:], data[1:])
	}
	conn.Write(sendBuf)
	time.Sleep(1 * time.Millisecond)
	return 0
}
// TestPropagateTxnOnError verifies that DistSender.sendChunk properly
// propagates the txn data to a next iteration. Use txn.Writing field to
// verify that.
func TestPropagateTxnOnError(t *testing.T) {
	defer leaktest.AfterTest(t)()

	// Set up a filter to so that the first CPut operation will
	// get a ReadWithinUncertaintyIntervalError.
	targetKey := roachpb.Key("b")
	var numGets int32

	ctx := server.NewTestContext()
	ctx.TestingKnobs.StoreTestingKnobs.TestingCommandFilter =
		func(fArgs storageutils.FilterArgs) *roachpb.Error {
			_, ok := fArgs.Req.(*roachpb.ConditionalPutRequest)
			if ok && fArgs.Req.Header().Key.Equal(targetKey) {
				if atomic.AddInt32(&numGets, 1) == 1 {
					z := roachpb.ZeroTimestamp
					pErr := roachpb.NewReadWithinUncertaintyIntervalError(z, z)
					return roachpb.NewErrorWithTxn(pErr, fArgs.Hdr.Txn)
				}
			}
			return nil
		}
	s := server.StartTestServerWithContext(t, ctx)
	defer s.Stop()
	db := setupMultipleRanges(t, s, "b")

	// Set the initial value on the target key "b".
	origVal := "val"
	if pErr := db.Put(targetKey, origVal); pErr != nil {
		t.Fatal(pErr)
	}

	// The following txn creates a batch request that is split
	// into two requests: Put and CPut. The CPut operation will
	// get a ReadWithinUncertaintyIntervalError and the txn will be
	// retried.
	epoch := 0
	if pErr := db.Txn(func(txn *client.Txn) *roachpb.Error {
		epoch++
		if epoch >= 2 {
			// Writing must be true since we ran the BeginTransaction command.
			if !txn.Proto.Writing {
				t.Errorf("unexpected non-writing txn")
			}
		} else {
			// Writing must be false since we haven't run any write command.
			if txn.Proto.Writing {
				t.Errorf("unexpected writing txn")
			}
		}

		b := txn.NewBatch()
		b.Put("a", "val")
		b.CPut(targetKey, "new_val", origVal)
		pErr := txn.CommitInBatch(b)
		if epoch == 1 {
			if _, ok := pErr.GetDetail().(*roachpb.ReadWithinUncertaintyIntervalError); ok {
				if !pErr.GetTxn().Writing {
					t.Errorf("unexpected non-writing txn on error")
				}
			} else {
				t.Errorf("expected ReadWithinUncertaintyIntervalError, but got: %s", pErr)
			}
		}
		return pErr
	}); pErr != nil {
		t.Errorf("unexpected error on transactional Puts: %s", pErr)
	}

	if epoch != 2 {
		t.Errorf("unexpected epoch; the txn must be retried exactly once, but got %d", epoch)
	}
}