Repository: googleapis/gapic-generator-go
Pull request #122 (2019-04-10 08:36:36)

SampleGen: LRO

hzyi-google: @googleapis/samplegen PTAL
hzyi-google: Binary removed. PTAL @noahdietz 
vchudnov-g: (arg, I thought I submitted my review yesterday, but as I often do, I forgot to hit "Submit") :frowning_face: 

Patch:
diff --git a/cmd/gen-go-sample/gapic.go b/cmd/gen-go-sample/gapic.go
index 813603e..5a37fd3 100644
--- a/cmd/gen-go-sample/gapic.go
+++ b/cmd/gen-go-sample/gapic.go
@@ -33,6 +33,8 @@ type GAPICMethod struct {
 
 	// map[fieldName]ResourceName.EntityName
 	FieldNamePatterns map[string]string `yaml:"field_name_patterns"`
+
+	LongRunning LongRunningConfig `yaml: "long_running"`
 }
 
 type SampleValueSet struct {
@@ -75,3 +77,9 @@ type ResourceName struct {
 	EntityName  string `yaml:"entity_name"`
 	NamePattern string `yaml:"name_pattern"`
 }
+
+// All other fields are left out because samples do not need to know polling config, and we are moving to annotations anyway
+type LongRunningConfig struct {
+	ReturnType   string `yaml: "return_type"`
+	MetadataType string `yaml: "metadata_type"`
+}
diff --git a/cmd/gen-go-sample/main.go b/cmd/gen-go-sample/main.go
index c6de1d9..379c2ae 100644
--- a/cmd/gen-go-sample/main.go
+++ b/cmd/gen-go-sample/main.go
@@ -373,11 +373,10 @@ func (g *generator) genSample(ifaceName string, methConf GAPICMethod, regTag str
 			return err
 		}
 	}
-
 	if meth.GetOutputType() == ".google.protobuf.Empty" {
 		err = g.emptyOut(meth, valSet)
-	} else if meth.GetOutputType() == ".google.protobuf.Operation" {
-		err = errors.E(nil, "LRO not supported yet")
+	} else if meth.GetOutputType() == ".google.longrunning.Operation" {
+		err = g.lro(meth, methConf, valSet)
 	} else if meth.GetServerStreaming() || meth.GetClientStreaming() {
 		err = errors.E(nil, "streaming methods not supported yet")
 	} else if pf, err2 := pagingField(g.descInfo, meth); err2 != nil {
@@ -485,6 +484,29 @@ func (g *generator) paging(meth *descriptor.MethodDescriptorProto, pf *descripto
 	return err
 }
 
+func (g *generator) lro(meth *descriptor.MethodDescriptorProto, methConf GAPICMethod, valSet SampleValueSet) error {
+	p := g.pt.Printf
+
+	p("op, err := c.%s(ctx, req)", meth.GetName())
+	p("if err != nil {")
+	p("  return err")
+	p("}")
+	p("")
+	p("resp, err := op.Wait(ctx)")
+	p("if err != nil {")
+	p("  return err")
+	p("}")
+	p("")
+
+	retType := methConf.LongRunning.ReturnType
+	if retType == "" {
+		return errors.E(nil, "LRO return type not given")
+	}
+
+	typ := initType{desc: g.descInfo.Type["."+retType]}
+	return g.handleOut(meth, valSet, &typ)
+}
+
 func (g *generator) handleOut(meth *descriptor.MethodDescriptorProto, valSet SampleValueSet, respTyp *initType) error {
 	st := newSymTab(nil)
 	if respTyp != nil {


Test patch:
diff --git a/cmd/gen-go-sample/main_test.go b/cmd/gen-go-sample/main_test.go
index b26c578..c344153 100644
--- a/cmd/gen-go-sample/main_test.go
+++ b/cmd/gen-go-sample/main_test.go
@@ -119,6 +119,18 @@ func TestSample_InitError(t *testing.T) {
 			t.Errorf("expected error from init config: %s", tst)
 		}
 	}
+
+	// missing LRO config
+	g.reset()
+
+	vs := SampleValueSet{
+		ID: "my_value_set",
+	}
+
+	if err := g.genSample("foo.FooService", GAPICMethod{Name: "LroMethod"}, "awesome_region", vs); err == nil {
+		t.Errorf("expected error from missing config")
+	}
+
 }
 
 func TestPaging(t *testing.T) {
@@ -135,6 +147,32 @@ func TestPaging(t *testing.T) {
 	compare(t, g, filepath.Join("testdata", "sample_paging.want"))
 }
 
+func TestLro(t *testing.T) {
+	t.Parallel()
+
+	g := initTestGenerator()
+
+	vs := SampleValueSet{
+		ID: "my_value_set",
+		OnSuccess: []OutputSpec{
+			{Print: []string{"x = %s", "$resp.a.x"}},
+		},
+	}
+
+	methConf := GAPICMethod{
+		Name: "LroMethod",
+		LongRunning: LongRunningConfig{
+			ReturnType:   "foo.lroReturnType",
+			MetadataType: "foo.lroMetadataType",
+		},
+	}
+
+	if err := g.genSample("foo.FooService", methConf, "awesome_region", vs); err != nil {
+		t.Fatal(err)
+	}
+	compare(t, g, filepath.Join("testdata", "sample_lro.want"))
+}
+
 func TestEmpty(t *testing.T) {
 	t.Parallel()
 
@@ -202,6 +240,19 @@ func initTestGenerator() *generator {
 		},
 	}
 
+	lroInType := &descriptor.DescriptorProto{
+		Name: proto.String("LroInType"),
+	}
+	lroReturnType := &descriptor.DescriptorProto{
+		Name: proto.String("lroReturnType"),
+		Field: []*descriptor.FieldDescriptorProto{
+			{Name: proto.String("a"), TypeName: proto.String(".foo.AType")},
+		},
+	}
+	lroMetadataType := &descriptor.DescriptorProto{
+		Name: proto.String("lroMetadataType"),
+	}
+
 	serv := &descriptor.ServiceDescriptorProto{
 		Name: proto.String("FooService"),
 		Method: []*descriptor.MethodDescriptorProto{
@@ -220,6 +271,11 @@ func initTestGenerator() *generator {
 				InputType:  proto.String(".foo.PageInType"),
 				OutputType: proto.String(".google.protobuf.Empty"),
 			},
+			{
+				Name:       proto.String("LroMethod"),
+				InputType:  proto.String(".foo.LroInType"),
+				OutputType: proto.String(".google.longrunning.Operation"),
+			},
 		},
 	}
 	file := &descriptor.FileDescriptorProto{
@@ -228,7 +284,7 @@ func initTestGenerator() *generator {
 		},
 		Package:     proto.String("foo"),
 		Service:     []*descriptor.ServiceDescriptorProto{serv},
-		MessageType: []*descriptor.DescriptorProto{inType, aType, pageInType, pageOutType},
+		MessageType: []*descriptor.DescriptorProto{inType, aType, pageInType, pageOutType, lroInType, lroReturnType, lroMetadataType},
 	}
 
 	return &generator{
diff --git a/cmd/gen-go-sample/testdata/sample_lro.want b/cmd/gen-go-sample/testdata/sample_lro.want
new file mode 100644
index 0000000..6ba0f1d
--- /dev/null
+++ b/cmd/gen-go-sample/testdata/sample_lro.want
@@ -0,0 +1,60 @@
+// Copyright 2018 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go_gapic. DO NOT EDIT.
+
+package main
+import(
+ "context"
+ "flag"
+ "fmt"
+ "log"
+
+foo "path.to/client/foo"
+foopb "path.to/pb/foo"
+)
+// [START awesome_region]
+
+func sampleLroMethod() error {
+	ctx := context.Background()
+	c, err := foo.NewClient(ctx)
+	if err != nil {
+		return err
+	}
+
+	req := &foopb.LroInType{
+	}
+	op, err := c.LroMethod(ctx, req)
+	if err != nil {
+		return err
+	}
+
+	resp, err := op.Wait(ctx)
+	if err != nil {
+		return err
+	}
+
+	fmt.Printf("x = %v\n", resp.GetA().GetX())
+	return nil
+}
+
+// [END awesome_region]
+
+func main() {
+	flag.Parse()
+	if err := sampleLroMethod(); err != nil {
+		log.Fatal(err)
+	}
+}
+