Skip to content

Commit

Permalink
Add basic tests for remaining handler and route types.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmalloc committed Oct 22, 2024
1 parent a5c5f7d commit 783eecf
Show file tree
Hide file tree
Showing 11 changed files with 256 additions and 41 deletions.
4 changes: 3 additions & 1 deletion config/staticconfig/analyze_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ func TestAnalyzer(t *testing.T) {
if err != nil {
return err
}
defer os.RemoveAll(dir)
t.Cleanup(func() {
os.RemoveAll(dir)
})

f, err := os.Create(filepath.Join(dir, "main.go"))
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions config/staticconfig/configurer.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func (c *configureContext) IsConfigurer(v ssa.Value) bool {

type configurerCall struct {
*ssa.CallCommon

Instruction ssa.CallInstruction
Fidelity config.Fidelity
}
Expand Down
9 changes: 9 additions & 0 deletions config/staticconfig/internal/ssax/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ import (
"golang.org/x/tools/go/ssa"
)

// IsZeroValue returns true if v is a constant value that represents the zero
// value for its type.
func IsZeroValue(v ssa.Value) bool {
if c, ok := Const(v).TryGet(); ok {
return c == nil
}
return false
}

// Const returns the singlar constant value of v if possible.
func Const(v ssa.Value) optional.Optional[constant.Value] {
return optional.TryTransform(
Expand Down
9 changes: 3 additions & 6 deletions config/staticconfig/internal/ssax/value.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package ssax

import (
"fmt"
"go/constant"
"go/token"

Expand All @@ -19,15 +18,13 @@ func StaticValue(v ssa.Value) optional.Optional[ssa.Value] {

case ssa.Instruction:
values := staticValuesFromInstruction(v)
if len(values) > 1 {
panic("did not expect multiple values")

Check warning on line 22 in config/staticconfig/internal/ssax/value.go

View check run for this annotation

Codecov / codecov/patch

config/staticconfig/internal/ssax/value.go#L22

Added line #L22 was not covered by tests
}

if len(values) == 1 {
fmt.Println("RESOLVED", values[0])
return values[0]
}

if len(values) > 1 {
panic("did not expect multiple values")
}
}

// TODO(jmalloc): This implementation is incomplete.
Expand Down
8 changes: 1 addition & 7 deletions config/staticconfig/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,7 @@ func analyzeRoutesCall(
b configbuilder.HandlerBuilder,
call configurerCall,
) {
routes, ok := resolveVariadic(b, call)
if !ok {
b.UpdateFidelity(config.Incomplete)
return
}

for _, r := range routes {
for r := range resolveVariadic(b, call) {
b.Route(func(b *configbuilder.RouteBuilder) {
b.UpdateFidelity(call.Fidelity)
analyzeRoute(ctx, b, r)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Aggregate
# Aggregate message handler

This test ensures that the static analyzer supports all aspects of configuring
an aggregate.
an aggregate handler.

```au:output au:group=matrix
valid application github.com/dogmatiq/enginekit/config/staticconfig.App (runtime type unavailable)
Expand Down
41 changes: 41 additions & 0 deletions config/staticconfig/testdata/handler-integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Integration message handler

This test ensures that the static analyzer supports all aspects of configuring
an integration handler.

```au:output au:group=matrix
valid application github.com/dogmatiq/enginekit/config/staticconfig.App (runtime type unavailable)
- valid identity app/0726ae0d-67e4-4a50-8a19-9f58eae38e51
- disabled valid integration github.com/dogmatiq/enginekit/config/staticconfig.Integration (runtime type unavailable)
- valid identity integration/b92431e6-3a7d-4235-a76f-541622c487ee
- valid handles-command route for github.com/dogmatiq/enginekit/enginetest/stubs.CommandStub[github.com/dogmatiq/enginekit/enginetest/stubs.TypeA] (runtime type unavailable)
- valid records-event route for github.com/dogmatiq/enginekit/enginetest/stubs.EventStub[github.com/dogmatiq/enginekit/enginetest/stubs.TypeA] (runtime type unavailable)
```

```go au:input au:group=matrix
package app

import "context"
import "github.com/dogmatiq/dogma"
import "github.com/dogmatiq/enginekit/enginetest/stubs"

type Integration struct {}

func (Integration) Configure(c dogma.IntegrationConfigurer) {
c.Identity("integration", "b92431e6-3a7d-4235-a76f-541622c487ee")
c.Routes(
dogma.HandlesCommand[stubs.CommandStub[stubs.TypeA]](),
dogma.RecordsEvent[stubs.EventStub[stubs.TypeA]](),
)
c.Disable()
}

type App struct{}

func (App) Configure(c dogma.ApplicationConfigurer) {
c.Identity("app", "0726ae0d-67e4-4a50-8a19-9f58eae38e51")
c.RegisterIntegration(Integration{})
}

func (Integration) HandleCommand(context.Context, dogma.IntegrationCommandScope, dogma.Command) error { return nil }
```
46 changes: 46 additions & 0 deletions config/staticconfig/testdata/handler-process.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Process message handler

This test ensures that the static analyzer supports all aspects of configuring
a process handler.

```au:output au:group=matrix
valid application github.com/dogmatiq/enginekit/config/staticconfig.App (runtime type unavailable)
- valid identity app/0726ae0d-67e4-4a50-8a19-9f58eae38e51
- disabled valid process github.com/dogmatiq/enginekit/config/staticconfig.Process (runtime type unavailable)
- valid identity process/4ff1b1c1-5c64-49bc-a547-c13f5bafad7d
- valid handles-event route for github.com/dogmatiq/enginekit/enginetest/stubs.EventStub[github.com/dogmatiq/enginekit/enginetest/stubs.TypeA] (runtime type unavailable)
- valid executes-command route for github.com/dogmatiq/enginekit/enginetest/stubs.CommandStub[github.com/dogmatiq/enginekit/enginetest/stubs.TypeA] (runtime type unavailable)
- valid schedules-timeout route for github.com/dogmatiq/enginekit/enginetest/stubs.TimeoutStub[github.com/dogmatiq/enginekit/enginetest/stubs.TypeA] (runtime type unavailable)
```

```go au:input au:group=matrix
package app

import "context"
import "github.com/dogmatiq/dogma"
import "github.com/dogmatiq/enginekit/enginetest/stubs"

type Process struct {}

func (Process) Configure(c dogma.ProcessConfigurer) {
c.Identity("process", "4ff1b1c1-5c64-49bc-a547-c13f5bafad7d")
c.Routes(
dogma.HandlesEvent[stubs.EventStub[stubs.TypeA]](),
dogma.ExecutesCommand[stubs.CommandStub[stubs.TypeA]](),
dogma.SchedulesTimeout[stubs.TimeoutStub[stubs.TypeA]](),
)
c.Disable()
}

type App struct{}

func (App) Configure(c dogma.ApplicationConfigurer) {
c.Identity("app", "0726ae0d-67e4-4a50-8a19-9f58eae38e51")
c.RegisterProcess(Process{})
}

func (Process) New() dogma.ProcessRoot { return nil }
func (Process) RouteEventToInstance(context.Context, dogma.Event) (string, bool, error) { return "", false, nil }
func (Process) HandleEvent(context.Context, dogma.ProcessRoot, dogma.ProcessEventScope, dogma.Event) error { return nil }
func (Process) HandleTimeout(context.Context, dogma.ProcessRoot, dogma.ProcessTimeoutScope, dogma.Timeout) error { return nil }
```
45 changes: 45 additions & 0 deletions config/staticconfig/testdata/handler-projection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Projection message handler

This test ensures that the static analyzer supports all aspects of configuring
a projection handler.

```au:output au:group=matrix
valid application github.com/dogmatiq/enginekit/config/staticconfig.App (runtime type unavailable)
- valid identity app/0726ae0d-67e4-4a50-8a19-9f58eae38e51
- disabled valid projection github.com/dogmatiq/enginekit/config/staticconfig.Projection (runtime type unavailable)
- valid identity projection/238d7498-515b-44b5-b6a8-914a08762ecc
- valid handles-event route for github.com/dogmatiq/enginekit/enginetest/stubs.EventStub[github.com/dogmatiq/enginekit/enginetest/stubs.TypeA] (runtime type unavailable)
```

```go au:input au:group=matrix
package app

import "context"
import "github.com/dogmatiq/dogma"
import "github.com/dogmatiq/enginekit/enginetest/stubs"

type Projection struct {}

func (Projection) Configure(c dogma.ProjectionConfigurer) {
c.Identity("projection", "238d7498-515b-44b5-b6a8-914a08762ecc")
c.Routes(
dogma.HandlesEvent[stubs.EventStub[stubs.TypeA]](),
)
// c.DeliveryPolicy(dogma.BroadcastProjectionDeliveryPolicy{
// PrimaryFirst: true,
// })
c.Disable()
}

type App struct{}

func (App) Configure(c dogma.ApplicationConfigurer) {
c.Identity("app", "0726ae0d-67e4-4a50-8a19-9f58eae38e51")
c.RegisterProjection(Projection{})
}

func (Projection) HandleEvent(context.Context, []byte, []byte, []byte, dogma.ProjectionEventScope, dogma.Event) (bool, error) { return false, nil }
func (Projection) Compact(context.Context, dogma.ProjectionCompactScope) error { return nil }
func (Projection) ResourceVersion(context.Context, []byte) ([]byte, error)
func (Projection) CloseResource(context.Context, []byte) error
```
79 changes: 79 additions & 0 deletions config/staticconfig/testdata/handler-with-unregistered-routes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Handler with unregistered routes

This test verifies that static analyzer does not include information about
routes that are constructed but never passed to the configurer's `Routes()`
method.

```au:output au:group=matrix
valid application github.com/dogmatiq/enginekit/config/staticconfig.App (runtime type unavailable)
- valid identity app/f2c08525-623e-4c76-851c-3172953269e3
- invalid integration github.com/dogmatiq/enginekit/config/staticconfig.Integration (runtime type unavailable)
- no "handles-command" routes are configured
- valid identity handler/ac391765-da58-4e7c-a478-e4725eb2b0e9
```

## No call to Routes()

```go au:input au:group=matrix
package app

import (
"context"
"github.com/dogmatiq/dogma"
"github.com/dogmatiq/enginekit/enginetest/stubs"
)

type Integration struct{}

func (Integration) Configure(c dogma.IntegrationConfigurer) {
c.Identity("handler", "ac391765-da58-4e7c-a478-e4725eb2b0e9")
dogma.HandlesCommand[stubs.CommandStub[stubs.TypeX]]()
}

type App struct{}

func (App) Configure(c dogma.ApplicationConfigurer) {
c.Identity("app", "f2c08525-623e-4c76-851c-3172953269e3")
c.RegisterIntegration(Integration{})
}

func (Integration) HandleCommand(context.Context, dogma.IntegrationCommandScope, dogma.Command) error { return nil }
```

## Route appended to slice after calling Routes()

```go au:input au:group=matrix
package app

import (
"context"
"github.com/dogmatiq/dogma"
"github.com/dogmatiq/enginekit/enginetest/stubs"
)

type Integration struct{}

func (Integration) Configure(c dogma.IntegrationConfigurer) {
c.Identity("handler", "ac391765-da58-4e7c-a478-e4725eb2b0e9")

var routes []dogma.IntegrationRoute

c.Routes(routes...)

routes = append(
routes,
dogma.HandlesCommand[stubs.CommandStub[stubs.TypeX]](),
)
}

type App struct{}

func (App) Configure(c dogma.ApplicationConfigurer) {
c.Identity("app", "f2c08525-623e-4c76-851c-3172953269e3")


c.RegisterIntegration(Integration{})
}

func (Integration) HandleCommand(context.Context, dogma.IntegrationCommandScope, dogma.Command) error { return nil }
```
51 changes: 26 additions & 25 deletions config/staticconfig/varargs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ package staticconfig

import (
"go/token"
"go/types"
"iter"

"github.com/dogmatiq/enginekit/config"
"github.com/dogmatiq/enginekit/config/internal/configbuilder"
"github.com/dogmatiq/enginekit/config/staticconfig/internal/ssax"
"golang.org/x/tools/go/ssa"
)

func findAllocation(v ssa.Value) (*ssa.Alloc, bool) {
// fmt.Println("***", v, reflect.TypeOf(v))
switch v := v.(type) {
case *ssa.Alloc:
return v, true
Expand Down Expand Up @@ -40,39 +40,40 @@ func isIndexOfArray(
}

Check warning on line 40 in config/staticconfig/varargs.go

View check run for this annotation

Codecov / codecov/patch

config/staticconfig/varargs.go#L39-L40

Added lines #L39 - L40 were not covered by tests
return ssax.AsInt(v.Index).TryGet()
}

return 0, false

Check warning on line 43 in config/staticconfig/varargs.go

View check run for this annotation

Codecov / codecov/patch

config/staticconfig/varargs.go#L43

Added line #L43 was not covered by tests
}

func resolveVariadic(
_ configbuilder.EntityBuilder,
b configbuilder.EntityBuilder,
call configurerCall,
) ([]ssa.Value, bool) {
n := len(call.Args) - 1
variadics := call.Args[n]

array, ok := findAllocation(variadics)
if !ok {
return nil, false
}

size := array.Type().Underlying().(*types.Pointer).Elem().(*types.Array).Len()
result := make([]ssa.Value, size)
) iter.Seq[ssa.Value] {
return func(yield func(ssa.Value) bool) {
variadics := call.Args[len(call.Args)-1]
if ssax.IsZeroValue(variadics) {
return
}

for b := range ssax.WalkDown(array.Block()) {
if !ssax.PathExists(b, call.Instruction.Block()) {
continue
array, ok := findAllocation(variadics)
if !ok {
b.UpdateFidelity(config.Incomplete)
return
}

Check warning on line 60 in config/staticconfig/varargs.go

View check run for this annotation

Codecov / codecov/patch

config/staticconfig/varargs.go#L58-L60

Added lines #L58 - L60 were not covered by tests

for inst := range ssax.InstructionsBefore(b, call.Instruction) {
switch inst := inst.(type) {
case *ssa.Store:
if i, ok := isIndexOfArray(array, inst.Addr); ok {
result[i] = inst.Val
for b := range ssax.WalkDown(array.Block()) {
if !ssax.PathExists(b, call.Instruction.Block()) {
continue

Check warning on line 64 in config/staticconfig/varargs.go

View check run for this annotation

Codecov / codecov/patch

config/staticconfig/varargs.go#L64

Added line #L64 was not covered by tests
}

for inst := range ssax.InstructionsBefore(b, call.Instruction) {
switch inst := inst.(type) {
case *ssa.Store:
if _, ok := isIndexOfArray(array, inst.Addr); ok {
if !yield(inst.Val) {
return
}

Check warning on line 73 in config/staticconfig/varargs.go

View check run for this annotation

Codecov / codecov/patch

config/staticconfig/varargs.go#L72-L73

Added lines #L72 - L73 were not covered by tests
}
}
}
}
}

return result, true
}

0 comments on commit 783eecf

Please sign in to comment.