Skip to content

Commit

Permalink
Adds interface generation to service APIs
Browse files Browse the repository at this point in the history
This change adds generation of interfaces for the service APIs. Each service now has a sub package <serviceName>iface which contains an interface for that service's operations. The interfaces can be used to facilitate unit testing with tools like mockery to generate mocks of service API.

fixes #88
  • Loading branch information
Jason Del Ponte committed Apr 17, 2015
1 parent e5ae197 commit 9f2cef4
Show file tree
Hide file tree
Showing 47 changed files with 2,824 additions and 10 deletions.
2 changes: 1 addition & 1 deletion internal/fixtures/integration/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ var (

var tplTestCase = template.Must(template.New("testcase").Parse(`
func Test{{ .TestName }}(t *testing.T) {
client := {{ .API.PackageName }}.New(nil)
client := {{ .API.NewAPIGoCodeWithPkgName "nil" }}
resp, e := client.{{ .API.ExportableName .Operation }}({{ .InputCode }})
err := aws.Error(e)
_, _, _ = resp, e, err // avoid unused warnings
Expand Down
45 changes: 45 additions & 0 deletions internal/model/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ func (a *API) PackageName() string {
return strings.ToLower(a.StructName())
}

// Returns the package name for the interface.
func (a *API) InterfacePackageName() string {
return a.PackageName() + "iface"
}

var nameRegex = regexp.MustCompile(`^Amazon|AWS\s*|\(.*|\s+|\W+`)

// StructName returns the service struct name for a given service
Expand Down Expand Up @@ -281,3 +286,43 @@ func (a *API) ExampleGoCode() string {
)
return util.GoFmt(code)
}

var tplInterface = template.Must(template.New("interface").Parse(`
type {{ .StructName }} interface {
{{ range $_, $o := .OperationList }}
{{ $o.InterfaceSignature }}
{{ end }}
}
`))

// Returns the go code for the service's API operations as an interface{}.
// Assumes that the interface is being created in a different package than
// the service API's package.
func (a *API) InterfaceGoCode() string {
a.resetImports()
a.imports = map[string]bool{
"github.com/awslabs/aws-sdk-go/service/" + a.PackageName(): true,
}

var buf bytes.Buffer
err := tplInterface.Execute(&buf, &struct {
StructName string
OperationList []*Operation
}{
StructName: a.StructName() + "API",
OperationList: a.OperationList(),
})

if err != nil {
panic(err)
}

code := a.importsGoCode() + strings.TrimSpace(buf.String())
return util.GoFmt(code)
}

// Returns a string of instantiating the API prefixed with its package name.
// Takes a string depicting the Config.
func (a *API) NewAPIGoCodeWithPkgName(cfg string) string {
return fmt.Sprintf("%s.New(%s)", a.PackageName(), cfg)
}
17 changes: 16 additions & 1 deletion internal/model/api/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,24 @@ func (o *Operation) GoCode() string {
return strings.TrimSpace(util.GoFmt(buf.String()))
}

var tplInfSig = template.Must(template.New("opsig").Parse(`
{{ .ExportedName }}({{ .InputRef.GoTypeWithPkgName }}) ({{ .OutputRef.GoTypeWithPkgName }}, error)
`))

// Returns a string representing the Operation's interface{} functional signature.
func (o *Operation) InterfaceSignature() string {
var buf bytes.Buffer
err := tplInfSig.Execute(&buf, o)
if err != nil {
panic(err)
}

return strings.TrimSpace(util.GoFmt(buf.String()))
}

var tplExample = template.Must(template.New("operationExample").Parse(`
func Example{{ .API.StructName }}_{{ .ExportedName }}() {
svc := {{ .API.PackageName }}.New(nil)
svc := {{ .API.NewAPIGoCodeWithPkgName "nil" }}
{{ .ExampleInput }}
resp, err := svc.{{ .ExportedName }}(params)
Expand Down
43 changes: 35 additions & 8 deletions internal/model/api/shape.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,44 @@ func (s *Shape) MemberNames() []string {
return names
}

// Returns a shape's type as a string with the package name in <packageName>.<type> format.
// package naming only applies to structures.
func (s *Shape) GoTypeWithPkgName() string {
return goType(s, true)
}

// Returns a shape's Go type
func (s *Shape) GoType() string {
return goType(s, false)
}

// Returns a shape ref's Go type.
func (ref *ShapeRef) GoType() string {
if ref.Shape == nil {
panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
}

return ref.Shape.GoType()
}

// Returns a shape's type as a string with the package name in <packageName>.<type> format.
// package naming only applies to structures.
func (ref *ShapeRef) GoTypeWithPkgName() string {
if ref.Shape == nil {
panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
}

return ref.Shape.GoTypeWithPkgName()
}

// Returns a string version of the Shape's type.
// If withPkgName is true, the package name will be added as a prefix
func goType(s *Shape, withPkgName bool) string {
switch s.Type {
case "structure":
if withPkgName {
return fmt.Sprintf("*%s.%s", s.API.PackageName(), s.ShapeName)
}
return "*" + s.ShapeName
case "map":
return "*map[string]" + s.ValueRef.GoType()
Expand All @@ -96,14 +131,6 @@ func (s *Shape) GoType() string {
}
}

func (ref *ShapeRef) GoType() string {
if ref.Shape == nil {
panic(fmt.Errorf("missing shape definition on reference for %#v", ref))
}

return ref.Shape.GoType()
}

func (s *Shape) GoTypeElem() string {
t := s.GoType()
if strings.HasPrefix(t, "*") {
Expand Down
7 changes: 7 additions & 0 deletions internal/model/cli/gen-api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func newGenerateInfo(modelFile, svcPath string) *generateInfo {
// ensure the directory exists
pkgDir := filepath.Join(svcPath, g.API.PackageName())
os.MkdirAll(pkgDir, 0775)
os.MkdirAll(filepath.Join(pkgDir, g.API.InterfacePackageName()), 0775)

g.PackageDir = pkgDir

Expand Down Expand Up @@ -105,6 +106,7 @@ func main() {
g.writeAPIFile()
g.writeExamplesFile()
g.writeServiceFile()
g.writeInterfaceFile()
}
}
}()
Expand All @@ -122,6 +124,11 @@ func (g *generateInfo) writeServiceFile() {
ioutil.WriteFile(file, []byte("package "+g.API.PackageName()+"\n\n"+g.API.ServiceGoCode()), 0664)
}

func (g *generateInfo) writeInterfaceFile() {
file := filepath.Join(g.PackageDir, g.API.InterfacePackageName(), "interface.go")
ioutil.WriteFile(file, []byte("package "+g.API.InterfacePackageName()+"\n\n"+g.API.InterfaceGoCode()), 0664)
}

const note = "// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT."

func (g *generateInfo) writeAPIFile() {
Expand Down
97 changes: 97 additions & 0 deletions service/autoscaling/autoscalingiface/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package autoscalingiface

import (
"github.com/awslabs/aws-sdk-go/service/autoscaling"
)

type AutoScalingAPI interface {
AttachInstances(*autoscaling.AttachInstancesInput) (*autoscaling.AttachInstancesOutput, error)

CompleteLifecycleAction(*autoscaling.CompleteLifecycleActionInput) (*autoscaling.CompleteLifecycleActionOutput, error)

CreateAutoScalingGroup(*autoscaling.CreateAutoScalingGroupInput) (*autoscaling.CreateAutoScalingGroupOutput, error)

CreateLaunchConfiguration(*autoscaling.CreateLaunchConfigurationInput) (*autoscaling.CreateLaunchConfigurationOutput, error)

CreateOrUpdateTags(*autoscaling.CreateOrUpdateTagsInput) (*autoscaling.CreateOrUpdateTagsOutput, error)

DeleteAutoScalingGroup(*autoscaling.DeleteAutoScalingGroupInput) (*autoscaling.DeleteAutoScalingGroupOutput, error)

DeleteLaunchConfiguration(*autoscaling.DeleteLaunchConfigurationInput) (*autoscaling.DeleteLaunchConfigurationOutput, error)

DeleteLifecycleHook(*autoscaling.DeleteLifecycleHookInput) (*autoscaling.DeleteLifecycleHookOutput, error)

DeleteNotificationConfiguration(*autoscaling.DeleteNotificationConfigurationInput) (*autoscaling.DeleteNotificationConfigurationOutput, error)

DeletePolicy(*autoscaling.DeletePolicyInput) (*autoscaling.DeletePolicyOutput, error)

DeleteScheduledAction(*autoscaling.DeleteScheduledActionInput) (*autoscaling.DeleteScheduledActionOutput, error)

DeleteTags(*autoscaling.DeleteTagsInput) (*autoscaling.DeleteTagsOutput, error)

DescribeAccountLimits(*autoscaling.DescribeAccountLimitsInput) (*autoscaling.DescribeAccountLimitsOutput, error)

DescribeAdjustmentTypes(*autoscaling.DescribeAdjustmentTypesInput) (*autoscaling.DescribeAdjustmentTypesOutput, error)

DescribeAutoScalingGroups(*autoscaling.DescribeAutoScalingGroupsInput) (*autoscaling.DescribeAutoScalingGroupsOutput, error)

DescribeAutoScalingInstances(*autoscaling.DescribeAutoScalingInstancesInput) (*autoscaling.DescribeAutoScalingInstancesOutput, error)

DescribeAutoScalingNotificationTypes(*autoscaling.DescribeAutoScalingNotificationTypesInput) (*autoscaling.DescribeAutoScalingNotificationTypesOutput, error)

DescribeLaunchConfigurations(*autoscaling.DescribeLaunchConfigurationsInput) (*autoscaling.DescribeLaunchConfigurationsOutput, error)

DescribeLifecycleHookTypes(*autoscaling.DescribeLifecycleHookTypesInput) (*autoscaling.DescribeLifecycleHookTypesOutput, error)

DescribeLifecycleHooks(*autoscaling.DescribeLifecycleHooksInput) (*autoscaling.DescribeLifecycleHooksOutput, error)

DescribeMetricCollectionTypes(*autoscaling.DescribeMetricCollectionTypesInput) (*autoscaling.DescribeMetricCollectionTypesOutput, error)

DescribeNotificationConfigurations(*autoscaling.DescribeNotificationConfigurationsInput) (*autoscaling.DescribeNotificationConfigurationsOutput, error)

DescribePolicies(*autoscaling.DescribePoliciesInput) (*autoscaling.DescribePoliciesOutput, error)

DescribeScalingActivities(*autoscaling.DescribeScalingActivitiesInput) (*autoscaling.DescribeScalingActivitiesOutput, error)

DescribeScalingProcessTypes(*autoscaling.DescribeScalingProcessTypesInput) (*autoscaling.DescribeScalingProcessTypesOutput, error)

DescribeScheduledActions(*autoscaling.DescribeScheduledActionsInput) (*autoscaling.DescribeScheduledActionsOutput, error)

DescribeTags(*autoscaling.DescribeTagsInput) (*autoscaling.DescribeTagsOutput, error)

DescribeTerminationPolicyTypes(*autoscaling.DescribeTerminationPolicyTypesInput) (*autoscaling.DescribeTerminationPolicyTypesOutput, error)

DetachInstances(*autoscaling.DetachInstancesInput) (*autoscaling.DetachInstancesOutput, error)

DisableMetricsCollection(*autoscaling.DisableMetricsCollectionInput) (*autoscaling.DisableMetricsCollectionOutput, error)

EnableMetricsCollection(*autoscaling.EnableMetricsCollectionInput) (*autoscaling.EnableMetricsCollectionOutput, error)

EnterStandby(*autoscaling.EnterStandbyInput) (*autoscaling.EnterStandbyOutput, error)

ExecutePolicy(*autoscaling.ExecutePolicyInput) (*autoscaling.ExecutePolicyOutput, error)

ExitStandby(*autoscaling.ExitStandbyInput) (*autoscaling.ExitStandbyOutput, error)

PutLifecycleHook(*autoscaling.PutLifecycleHookInput) (*autoscaling.PutLifecycleHookOutput, error)

PutNotificationConfiguration(*autoscaling.PutNotificationConfigurationInput) (*autoscaling.PutNotificationConfigurationOutput, error)

PutScalingPolicy(*autoscaling.PutScalingPolicyInput) (*autoscaling.PutScalingPolicyOutput, error)

PutScheduledUpdateGroupAction(*autoscaling.PutScheduledUpdateGroupActionInput) (*autoscaling.PutScheduledUpdateGroupActionOutput, error)

RecordLifecycleActionHeartbeat(*autoscaling.RecordLifecycleActionHeartbeatInput) (*autoscaling.RecordLifecycleActionHeartbeatOutput, error)

ResumeProcesses(*autoscaling.ScalingProcessQuery) (*autoscaling.ResumeProcessesOutput, error)

SetDesiredCapacity(*autoscaling.SetDesiredCapacityInput) (*autoscaling.SetDesiredCapacityOutput, error)

SetInstanceHealth(*autoscaling.SetInstanceHealthInput) (*autoscaling.SetInstanceHealthOutput, error)

SuspendProcesses(*autoscaling.ScalingProcessQuery) (*autoscaling.SuspendProcessesOutput, error)

TerminateInstanceInAutoScalingGroup(*autoscaling.TerminateInstanceInAutoScalingGroupInput) (*autoscaling.TerminateInstanceInAutoScalingGroupOutput, error)

UpdateAutoScalingGroup(*autoscaling.UpdateAutoScalingGroupInput) (*autoscaling.UpdateAutoScalingGroupOutput, error)
}
41 changes: 41 additions & 0 deletions service/cloudformation/cloudformationiface/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cloudformationiface

import (
"github.com/awslabs/aws-sdk-go/service/cloudformation"
)

type CloudFormationAPI interface {
CancelUpdateStack(*cloudformation.CancelUpdateStackInput) (*cloudformation.CancelUpdateStackOutput, error)

CreateStack(*cloudformation.CreateStackInput) (*cloudformation.CreateStackOutput, error)

DeleteStack(*cloudformation.DeleteStackInput) (*cloudformation.DeleteStackOutput, error)

DescribeStackEvents(*cloudformation.DescribeStackEventsInput) (*cloudformation.DescribeStackEventsOutput, error)

DescribeStackResource(*cloudformation.DescribeStackResourceInput) (*cloudformation.DescribeStackResourceOutput, error)

DescribeStackResources(*cloudformation.DescribeStackResourcesInput) (*cloudformation.DescribeStackResourcesOutput, error)

DescribeStacks(*cloudformation.DescribeStacksInput) (*cloudformation.DescribeStacksOutput, error)

EstimateTemplateCost(*cloudformation.EstimateTemplateCostInput) (*cloudformation.EstimateTemplateCostOutput, error)

GetStackPolicy(*cloudformation.GetStackPolicyInput) (*cloudformation.GetStackPolicyOutput, error)

GetTemplate(*cloudformation.GetTemplateInput) (*cloudformation.GetTemplateOutput, error)

GetTemplateSummary(*cloudformation.GetTemplateSummaryInput) (*cloudformation.GetTemplateSummaryOutput, error)

ListStackResources(*cloudformation.ListStackResourcesInput) (*cloudformation.ListStackResourcesOutput, error)

ListStacks(*cloudformation.ListStacksInput) (*cloudformation.ListStacksOutput, error)

SetStackPolicy(*cloudformation.SetStackPolicyInput) (*cloudformation.SetStackPolicyOutput, error)

SignalResource(*cloudformation.SignalResourceInput) (*cloudformation.SignalResourceOutput, error)

UpdateStack(*cloudformation.UpdateStackInput) (*cloudformation.UpdateStackOutput, error)

ValidateTemplate(*cloudformation.ValidateTemplateInput) (*cloudformation.ValidateTemplateOutput, error)
}
49 changes: 49 additions & 0 deletions service/cloudfront/cloudfrontiface/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package cloudfrontiface

import (
"github.com/awslabs/aws-sdk-go/service/cloudfront"
)

type CloudFrontAPI interface {
CreateCloudFrontOriginAccessIdentity(*cloudfront.CreateCloudFrontOriginAccessIdentityInput) (*cloudfront.CreateCloudFrontOriginAccessIdentityOutput, error)

CreateDistribution(*cloudfront.CreateDistributionInput) (*cloudfront.CreateDistributionOutput, error)

CreateInvalidation(*cloudfront.CreateInvalidationInput) (*cloudfront.CreateInvalidationOutput, error)

CreateStreamingDistribution(*cloudfront.CreateStreamingDistributionInput) (*cloudfront.CreateStreamingDistributionOutput, error)

DeleteCloudFrontOriginAccessIdentity(*cloudfront.DeleteCloudFrontOriginAccessIdentityInput) (*cloudfront.DeleteCloudFrontOriginAccessIdentityOutput, error)

DeleteDistribution(*cloudfront.DeleteDistributionInput) (*cloudfront.DeleteDistributionOutput, error)

DeleteStreamingDistribution(*cloudfront.DeleteStreamingDistributionInput) (*cloudfront.DeleteStreamingDistributionOutput, error)

GetCloudFrontOriginAccessIdentity(*cloudfront.GetCloudFrontOriginAccessIdentityInput) (*cloudfront.GetCloudFrontOriginAccessIdentityOutput, error)

GetCloudFrontOriginAccessIdentityConfig(*cloudfront.GetCloudFrontOriginAccessIdentityConfigInput) (*cloudfront.GetCloudFrontOriginAccessIdentityConfigOutput, error)

GetDistribution(*cloudfront.GetDistributionInput) (*cloudfront.GetDistributionOutput, error)

GetDistributionConfig(*cloudfront.GetDistributionConfigInput) (*cloudfront.GetDistributionConfigOutput, error)

GetInvalidation(*cloudfront.GetInvalidationInput) (*cloudfront.GetInvalidationOutput, error)

GetStreamingDistribution(*cloudfront.GetStreamingDistributionInput) (*cloudfront.GetStreamingDistributionOutput, error)

GetStreamingDistributionConfig(*cloudfront.GetStreamingDistributionConfigInput) (*cloudfront.GetStreamingDistributionConfigOutput, error)

ListCloudFrontOriginAccessIdentities(*cloudfront.ListCloudFrontOriginAccessIdentitiesInput) (*cloudfront.ListCloudFrontOriginAccessIdentitiesOutput, error)

ListDistributions(*cloudfront.ListDistributionsInput) (*cloudfront.ListDistributionsOutput, error)

ListInvalidations(*cloudfront.ListInvalidationsInput) (*cloudfront.ListInvalidationsOutput, error)

ListStreamingDistributions(*cloudfront.ListStreamingDistributionsInput) (*cloudfront.ListStreamingDistributionsOutput, error)

UpdateCloudFrontOriginAccessIdentity(*cloudfront.UpdateCloudFrontOriginAccessIdentityInput) (*cloudfront.UpdateCloudFrontOriginAccessIdentityOutput, error)

UpdateDistribution(*cloudfront.UpdateDistributionInput) (*cloudfront.UpdateDistributionOutput, error)

UpdateStreamingDistribution(*cloudfront.UpdateStreamingDistributionInput) (*cloudfront.UpdateStreamingDistributionOutput, error)
}
Loading

0 comments on commit 9f2cef4

Please sign in to comment.