Browse Source

Merge pull request #8010 from heyitsanthony/json-txn

e2e: test txn over grpc json
Anthony Romano 8 years ago
parent
commit
0c923bdf11
3 changed files with 62 additions and 2 deletions
  1. 9 0
      Documentation/dev-guide/api_grpc_gateway.md
  2. 51 0
      e2e/v3_curl_test.go
  3. 2 2
      etcdserver/api/v3rpc/key.go

+ 9 - 0
Documentation/dev-guide/api_grpc_gateway.md

@@ -38,6 +38,15 @@ curl -L http://localhost:2379/v3alpha/kv/put \
 # {"result":{"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"2","raft_term":"2"},"events":[{"kv":{"key":"Zm9v","create_revision":"2","mod_revision":"2","version":"1","value":"YmFy"}}]}}
 ```
 
+Use `curl` to issue a transaction:
+
+```bash
+curl -L http://localhost:2379/v3alpha/kv/txn \
+	-X POST \
+	-d '{"compare":[{"target":"CREATE","key":"Zm9v","createRevision":"2"}],"success":[{"requestPut":{"key":"Zm9v","value":"YmFy"}}]}'
+# {"header":{"cluster_id":"12585971608760269493","member_id":"13847567121247652255","revision":"3","raft_term":"2"},"succeeded":true,"responses":[{"response_put":{"header":{"revision":"3"}}}]}
+```
+
 ## Swagger
 
 Generated [Swagger][swagger] API definitions can be found at [rpc.swagger.json][swagger-doc].

+ 51 - 0
e2e/v3_curl_test.go

@@ -20,6 +20,8 @@ import (
 
 	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
 	"github.com/coreos/etcd/pkg/testutil"
+
+	"github.com/grpc-ecosystem/grpc-gateway/runtime"
 )
 
 func TestV3CurlPutGetNoTLS(t *testing.T)     { testCurlPutGetGRPCGateway(t, &configNoTLS) }
@@ -111,3 +113,52 @@ func TestV3CurlWatch(t *testing.T) {
 		t.Fatal(err)
 	}
 }
+
+func TestV3CurlTxn(t *testing.T) {
+	defer testutil.AfterTest(t)
+	epc, err := newEtcdProcessCluster(&configNoTLS)
+	if err != nil {
+		t.Fatalf("could not start etcd process cluster (%v)", err)
+	}
+	defer func() {
+		if cerr := epc.Close(); err != nil {
+			t.Fatalf("error closing etcd processes (%v)", cerr)
+		}
+	}()
+
+	txn := &pb.TxnRequest{
+		Compare: []*pb.Compare{
+			{
+				Key:         []byte("foo"),
+				Result:      pb.Compare_EQUAL,
+				Target:      pb.Compare_CREATE,
+				TargetUnion: &pb.Compare_CreateRevision{0},
+			},
+		},
+		Success: []*pb.RequestOp{
+			{
+				Request: &pb.RequestOp_RequestPut{
+					RequestPut: &pb.PutRequest{
+						Key:   []byte("foo"),
+						Value: []byte("bar"),
+					},
+				},
+			},
+		},
+	}
+	m := &runtime.JSONPb{}
+	jsonDat, jerr := m.Marshal(txn)
+	if jerr != nil {
+		t.Fatal(jerr)
+	}
+	expected := `"succeeded":true,"responses":[{"response_put":{"header":{"revision":"2"}}}]`
+	if err = cURLPost(epc, cURLReq{endpoint: "/v3alpha/kv/txn", value: string(jsonDat), expected: expected}); err != nil {
+		t.Fatalf("failed txn with curl (%v)", err)
+	}
+
+	// was crashing etcd server
+	malformed := `{"compare":[{"result":0,"target":1,"key":"Zm9v","TargetUnion":null}],"success":[{"Request":{"RequestPut":{"key":"Zm9v","value":"YmFy"}}}]}`
+	if err = cURLPost(epc, cURLReq{endpoint: "/v3alpha/kv/txn", value: malformed, expected: "error"}); err != nil {
+		t.Fatalf("failed put with curl (%v)", err)
+	}
+}

+ 2 - 2
etcdserver/api/v3rpc/key.go

@@ -253,8 +253,8 @@ func checkRequestOp(u *pb.RequestOp) error {
 			return checkDeleteRequest(uv.RequestDeleteRange)
 		}
 	default:
-		// empty op
-		return nil
+		// empty op / nil entry
+		return rpctypes.ErrGRPCKeyNotFound
 	}
 	return nil
 }