Skip to content

Commit

Permalink
Merge pull request #263 from dogmatiq/fix-parsing-msg-on-handlers
Browse files Browse the repository at this point in the history
Fix parsing indirect calls to handler `.Configure()` method.
  • Loading branch information
danilvpetrov authored Jan 15, 2024
2 parents 2eb058a + 8671f61 commit f7436d1
Show file tree
Hide file tree
Showing 10 changed files with 345 additions and 49 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ The format is based on [Keep a Changelog], and this project adheres to
[keep a changelog]: https://keepachangelog.com/en/1.0.0/
[semantic versioning]: https://semver.org/spec/v2.0.0.html

## [Unreleased]

### Fixed

- Fix parsing indirect calls to handler's `.Configure()` method.

## [0.12.1] - 2023-05-04

### Changed
Expand Down
12 changes: 6 additions & 6 deletions static/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,12 @@ func addHandlerFromConfigureMethod(
switch c.Common().Method.Name() {
case "Identity":
hdr.IdentityValue = analyzeIdentityCall(c)
case "Routes":
addMessagesFromRoutes(
c.Common().Value.Parent(),
hdr.MessageNamesValue.Produced,
hdr.MessageNamesValue.Consumed,
)
case "ConsumesCommandType":
addMessageFromArguments(
args,
Expand Down Expand Up @@ -326,12 +332,6 @@ func addHandlerFromConfigureMethod(
}
}

addMessagesFromRoutes(
method,
hdr.MessageNamesValue.Produced,
hdr.MessageNamesValue.Consumed,
)

hs.Add(hdr)
}

Expand Down
25 changes: 0 additions & 25 deletions static/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,31 +169,6 @@ var _ = Describe("func FromPackages() (application detection)", func() {
})
})

When("a handler with a non-pointer methodset is registered as a pointer", func() {
It("includes the handler in the application configuration", func() {
cfg := packages.Config{
Mode: packages.LoadAllSyntax,
Dir: "testdata/apps/pointer-handler-with-non-pointer-methodset",
}

pkgs := loadPackages(cfg)

apps := FromPackages(pkgs)
Expect(apps).To(HaveLen(1))
Expect(apps[0].Handlers().Aggregates()).To(HaveLen(1))

a := apps[0].Handlers().Aggregates()[0]
Expect(a.Identity()).To(
Equal(
configkit.Identity{
Name: "<aggregate>",
Key: "dad3b670-0852-4711-9efb-af25679734ee",
},
),
)
})
})

When("an application in the package has multiple handlers", func() {
It("returns all messages consumed or produced by all handlers", func() {
cfg := packages.Config{
Expand Down
135 changes: 135 additions & 0 deletions static/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -855,4 +855,139 @@ var _ = Describe("func FromPackages() (handler analysis)", func() {
Expect(apps[0].Handlers()).To(Equal(configkit.HandlerSet{}))
})
})

When("a handler with a non-pointer methodset is registered as a pointer", func() {
It("includes the handler in the application configuration", func() {
cfg := packages.Config{
Mode: packages.LoadAllSyntax,
Dir: "testdata/handlers/pointer-handler-with-non-pointer-methodset",
}

pkgs := loadPackages(cfg)

apps := FromPackages(pkgs)
Expect(apps).To(HaveLen(1))
Expect(apps[0].Handlers().Aggregates()).To(HaveLen(1))
Expect(apps[0].Handlers().Processes()).To(HaveLen(1))
Expect(apps[0].Handlers().Projections()).To(HaveLen(1))
Expect(apps[0].Handlers().Integrations()).To(HaveLen(1))

aggregate := apps[0].Handlers().Aggregates()[0]
Expect(aggregate.Identity()).To(
Equal(
configkit.Identity{
Name: "<aggregate>",
Key: "ee1814e3-194d-438a-916e-ee7766598646",
},
),
)
Expect(aggregate.TypeName()).To(
Equal(
"*github.com/dogmatiq/configkit/static/testdata/handlers/pointer-handler-with-non-pointer-methodset.AggregateHandler",
),
)
Expect(aggregate.HandlerType()).To(Equal(configkit.AggregateHandlerType))

Expect(aggregate.MessageNames()).To(Equal(
configkit.EntityMessageNames{
Consumed: message.NameRoles{
cfixtures.MessageATypeName: message.CommandRole,
cfixtures.MessageBTypeName: message.CommandRole,
},
Produced: message.NameRoles{
cfixtures.MessageCTypeName: message.EventRole,
cfixtures.MessageDTypeName: message.EventRole,
},
},
))

process := apps[0].Handlers().Processes()[0]
Expect(process.Identity()).To(
Equal(
configkit.Identity{
Name: "<process>",
Key: "39af6b34-5fa1-4f3a-b049-40a5e1d9b33b",
},
),
)
Expect(process.TypeName()).To(
Equal(
"*github.com/dogmatiq/configkit/static/testdata/handlers/pointer-handler-with-non-pointer-methodset.ProcessHandler",
),
)
Expect(process.HandlerType()).To(Equal(configkit.ProcessHandlerType))

Expect(process.MessageNames()).To(Equal(
configkit.EntityMessageNames{
Consumed: message.NameRoles{
cfixtures.MessageATypeName: message.EventRole,
cfixtures.MessageBTypeName: message.EventRole,
cfixtures.MessageETypeName: message.TimeoutRole,
cfixtures.MessageFTypeName: message.TimeoutRole,
},
Produced: message.NameRoles{
cfixtures.MessageCTypeName: message.CommandRole,
cfixtures.MessageDTypeName: message.CommandRole,
cfixtures.MessageETypeName: message.TimeoutRole,
cfixtures.MessageFTypeName: message.TimeoutRole,
},
},
))

projection := apps[0].Handlers().Projections()[0]
Expect(projection.Identity()).To(
Equal(
configkit.Identity{
Name: "<projection>",
Key: "3dfcd7cd-1f63-47a1-9be7-3242bd252423",
},
),
)
Expect(projection.TypeName()).To(
Equal(
"*github.com/dogmatiq/configkit/static/testdata/handlers/pointer-handler-with-non-pointer-methodset.ProjectionHandler",
),
)
Expect(projection.HandlerType()).To(Equal(configkit.ProjectionHandlerType))

Expect(projection.MessageNames()).To(Equal(
configkit.EntityMessageNames{
Consumed: message.NameRoles{
cfixtures.MessageATypeName: message.EventRole,
cfixtures.MessageBTypeName: message.EventRole,
},
Produced: message.NameRoles{},
},
))

integration := apps[0].Handlers().Integrations()[0]
Expect(integration.Identity()).To(
Equal(
configkit.Identity{
Name: "<integration>",
Key: "1425ca64-0448-4bfd-b18d-9fe63a95995f",
},
),
)
Expect(integration.TypeName()).To(
Equal(
"*github.com/dogmatiq/configkit/static/testdata/handlers/pointer-handler-with-non-pointer-methodset.IntegrationHandler",
),
)
Expect(integration.HandlerType()).To(Equal(configkit.IntegrationHandlerType))

Expect(integration.MessageNames()).To(Equal(
configkit.EntityMessageNames{
Consumed: message.NameRoles{
cfixtures.MessageATypeName: message.CommandRole,
cfixtures.MessageBTypeName: message.CommandRole,
},
Produced: message.NameRoles{
cfixtures.MessageCTypeName: message.EventRole,
cfixtures.MessageDTypeName: message.EventRole,
},
},
))
})
})
})

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ func (AggregateHandler) New() dogma.AggregateRoot {
// Configure configures the behavior of the engine as it relates to this
// handler.
func (AggregateHandler) Configure(c dogma.AggregateConfigurer) {
c.Identity("<aggregate>", "dad3b670-0852-4711-9efb-af25679734ee")
c.Identity("<aggregate>", "ee1814e3-194d-438a-916e-ee7766598646")

c.Routes(
dogma.HandlesCommand[fixtures.MessageA](),
dogma.RecordsEvent[fixtures.MessageB](),
dogma.HandlesCommand[fixtures.MessageB](),
dogma.RecordsEvent[fixtures.MessageC](),
dogma.RecordsEvent[fixtures.MessageD](),
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package app

import "github.com/dogmatiq/dogma"

// App implements dogma.Application interface.
type App struct{}

// Configure configures the behavior of the engine as it relates to this
// application.
func (App) Configure(c dogma.ApplicationConfigurer) {
c.Identity("<non-pointer-handler-registered-as-pointer>", "282653ad-9343-44f1-889e-a8b2b095b54b")

c.RegisterIntegration(&IntegrationHandler{})
c.RegisterProjection(&ProjectionHandler{})
c.RegisterAggregate(&AggregateHandler{})
c.RegisterProcess(&ProcessHandler{})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package app

import (
"context"
"time"

"github.com/dogmatiq/dogma"
"github.com/dogmatiq/dogma/fixtures"
)

// IntegrationHandler is a test implementation of
// dogma.IntegrationMessageHandler.
type IntegrationHandler struct{}

// Configure configures the behavior of the engine as it relates to this
// handler.
func (IntegrationHandler) Configure(c dogma.IntegrationConfigurer) {
c.Identity("<integration>", "1425ca64-0448-4bfd-b18d-9fe63a95995f")

c.Routes(
dogma.HandlesCommand[fixtures.MessageA](),
dogma.HandlesCommand[fixtures.MessageB](),
dogma.RecordsEvent[fixtures.MessageC](),
dogma.RecordsEvent[fixtures.MessageD](),
)
}

// RouteCommandToInstance returns the ID of the integration instance that is
// targetted by m.
func (IntegrationHandler) RouteCommandToInstance(m dogma.Message) string {
return "<integration>"
}

// HandleCommand handles a command message that has been routed to this handler.
func (IntegrationHandler) HandleCommand(
ctx context.Context,
s dogma.IntegrationCommandScope,
m dogma.Message,
) error {
return nil
}

// TimeoutHint returns a duration that is suitable for computing a deadline
// for the handling of the given message by this handler.
func (IntegrationHandler) TimeoutHint(m dogma.Message) time.Duration {
return 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package app

import (
"context"
"time"

"github.com/dogmatiq/dogma"
"github.com/dogmatiq/dogma/fixtures"
)

// Process is a process used for testing.
type Process struct{}

// ProcessHandler is a test implementation of dogma.ProcessMessageHandler.
type ProcessHandler struct{}

// New constructs a new process instance initialized with any default values and
// returns the process root.
func (ProcessHandler) New() dogma.ProcessRoot {
return Process{}
}

// Configure configures the behavior of the engine as it relates to this
// handler.
func (ProcessHandler) Configure(c dogma.ProcessConfigurer) {
c.Identity("<process>", "39af6b34-5fa1-4f3a-b049-40a5e1d9b33b")

c.Routes(
dogma.HandlesEvent[fixtures.MessageA](),
dogma.HandlesEvent[fixtures.MessageB](),
dogma.ExecutesCommand[fixtures.MessageC](),
dogma.ExecutesCommand[fixtures.MessageD](),
dogma.SchedulesTimeout[fixtures.MessageE](),
dogma.SchedulesTimeout[fixtures.MessageF](),
)
}

// RouteEventToInstance returns the ID of the process instance that is
// targeted by m.
func (ProcessHandler) RouteEventToInstance(
ctx context.Context,
m dogma.Message,
) (string, bool, error) {
return "<process>", true, nil
}

// HandleEvent handles an event message.
func (ProcessHandler) HandleEvent(
ctx context.Context,
r dogma.ProcessRoot,
s dogma.ProcessEventScope,
m dogma.Message,
) error {
return nil
}

// HandleTimeout handles a timeout message that has been scheduled with
// ProcessScope.ScheduleTimeout().
func (ProcessHandler) HandleTimeout(
ctx context.Context,
r dogma.ProcessRoot,
s dogma.ProcessTimeoutScope,
m dogma.Message,
) error {
return nil
}

// TimeoutHint returns a duration that is suitable for computing a deadline
// for the handling of the given message by this handler.
func (ProcessHandler) TimeoutHint(m dogma.Message) time.Duration {
return 0
}
Loading

0 comments on commit f7436d1

Please sign in to comment.