Skip to content

Commit

Permalink
Merge branch 'master' into docs-copy
Browse files Browse the repository at this point in the history
  • Loading branch information
sywhang authored May 8, 2023
2 parents f8f7c19 + ec9b096 commit 9c1a87d
Show file tree
Hide file tree
Showing 16 changed files with 260 additions and 44 deletions.
1 change: 1 addition & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
ignore:
- "docs/ex/**/*.go"
- "internal/e2e/**/*.go"

coverage:
range: 80..100
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
- No changes yet.
### Deprecated
- Deprecate `ShutdownTimeout` option.

## [1.19.1](https://github.com/uber-go/fx/compare/v1.18.0...v1.19.1) - 2023-01-10

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ GO_FILES = $(shell \
find . '(' -path '*/.*' -o -path './vendor' -o -path '*/testdata/*' ')' -prune \
-o -name '*.go' -print | cut -b3-)

MODULES = . ./tools ./docs
MODULES = . ./tools ./docs ./internal/e2e

# 'make cover' should not run on docs by default.
# We run that separately explicitly on a specific platform.
Expand Down
24 changes: 17 additions & 7 deletions annotated.go
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,8 @@ var _ Annotation = (*asAnnotation)(nil)
// w, r := a()
// return w, r
// }
//
// As annotation cannot be used in a function that returns an [Out] struct as a return type.
func As(interfaces ...interface{}) Annotation {
return &asAnnotation{targets: interfaces}
}
Expand Down Expand Up @@ -1322,6 +1324,9 @@ var _ Annotation = (*fromAnnotation)(nil)
// fx.Provide(func(r1 *FooRunner, r2 *BarRunner) *RunnerWraps {
// return NewRunnerWraps(r1, r2)
// })
//
// From annotation cannot be used in a function that takes an [In] struct as a
// parameter.
func From(interfaces ...interface{}) Annotation {
return &fromAnnotation{targets: interfaces}
}
Expand Down Expand Up @@ -1591,8 +1596,8 @@ func (ann *annotated) cleanUpAsResults() {
}

// checks and returns a non-nil error if the target function:
// - returns an fx.Out struct as a result.
// - takes in an fx.In struct as a parameter.
// - returns an fx.Out struct as a result and has either a ResultTags or an As annotation
// - takes in an fx.In struct as a parameter and has either a ParamTags or a From annotation
// - has an error result not as the last result.
func (ann *annotated) typeCheckOrigFn() error {
ft := reflect.TypeOf(ann.Target)
Expand All @@ -1608,18 +1613,23 @@ func (ann *annotated) typeCheckOrigFn() error {
if ot.Kind() != reflect.Struct {
continue
}
if len(ann.ResultTags) > 0 && dig.IsOut(reflect.New(ft.Out(i)).Elem().Interface()) {
return errors.New("fx.Out structs cannot be annotated with fx.ResultTags")
if !dig.IsOut(reflect.New(ft.Out(i)).Elem().Interface()) {
continue
}
if len(ann.ResultTags) > 0 || len(ann.As) > 0 {
return errors.New("fx.Out structs cannot be annotated with fx.ResultTags or fx.As")
}
}

for i := 0; i < ft.NumIn(); i++ {
it := ft.In(i)
if it.Kind() != reflect.Struct {
continue
}
if len(ann.ParamTags) > 0 && dig.IsIn(reflect.New(ft.In(i)).Elem().Interface()) {
return errors.New("fx.In structs cannot be annotated with fx.ParamTags")
if !dig.IsIn(reflect.New(ft.In(i)).Elem().Interface()) {
continue
}
if len(ann.ParamTags) > 0 || len(ann.From) > 0 {
return errors.New("fx.In structs cannot be annotated with fx.ParamTags or fx.From")
}
}
return nil
Expand Down
63 changes: 59 additions & 4 deletions annotated_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1427,7 +1427,7 @@ func TestAnnotate(t *testing.T) {
assert.Contains(t, err.Error(), "must provide constructor function, got 42 (int)")
})

t.Run("annotate a fx.Out", func(t *testing.T) {
t.Run("annotate a fx.Out with ResultTags", func(t *testing.T) {
t.Parallel()

type A struct {
Expand All @@ -1448,10 +1448,40 @@ func TestAnnotate(t *testing.T) {

err := app.Err()
require.Error(t, err)
assert.Contains(t, err.Error(), "fx.Out structs cannot be annotated")
assert.Contains(t, err.Error(), "fx.Out structs cannot be annotated with fx.ResultTags or fx.As")
})

t.Run("annotate a fx.In", func(t *testing.T) {
t.Run("annotate a fx.Out with As", func(t *testing.T) {
t.Parallel()

type I interface{}

type B struct {
// implements I
}

type Res struct {
fx.Out

AB B
}

f := func() Res {
return Res{AB: B{}}
}

app := NewForTest(t,
fx.Provide(
fx.Annotate(f, fx.As(new(I))),
),
)

err := app.Err()
require.Error(t, err)
assert.Contains(t, err.Error(), "fx.Out structs cannot be annotated with fx.ResultTags or fx.As")
})

t.Run("annotate a fx.In with ParamTags", func(t *testing.T) {
t.Parallel()

type A struct {
Expand All @@ -1471,7 +1501,32 @@ func TestAnnotate(t *testing.T) {
require.Error(t, err)
assert.NotContains(t, err.Error(), "invalid annotation function func(fx_test.A) string")
assert.Contains(t, err.Error(), "invalid annotation function func(fx_test.B) string")
assert.Contains(t, err.Error(), "fx.In structs cannot be annotated")
assert.Contains(t, err.Error(), "fx.In structs cannot be annotated with fx.ParamTags or fx.From")
})

t.Run("annotate a fx.In with From", func(t *testing.T) {
t.Parallel()

type I interface{}

type B struct {
// implements I
}

type Param struct {
fx.In
BInterface I
}

app := NewForTest(t,
fx.Provide(
fx.Annotate(func(p Param) string { return "ok" }, fx.From(new(B))),
),
)
err := app.Err()
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid annotation function func(fx_test.Param) string")
assert.Contains(t, err.Error(), "fx.In structs cannot be annotated with fx.ParamTags or fx.From")
})

t.Run("annotate fx.In with fx.ResultTags", func(t *testing.T) {
Expand Down
9 changes: 5 additions & 4 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -574,12 +574,12 @@ func (app *App) Run() {
// Historically, we do not os.Exit(0) even though most applications
// cede control to Fx with they call app.Run. To avoid a breaking
// change, never os.Exit for success.
if code := app.run(app.Done()); code != 0 {
if code := app.run(app.Wait()); code != 0 {
app.exit(code)
}
}

func (app *App) run(done <-chan os.Signal) (exitCode int) {
func (app *App) run(done <-chan ShutdownSignal) (exitCode int) {
startCtx, cancel := app.clock.WithTimeout(context.Background(), app.StartTimeout())
defer cancel()

Expand All @@ -588,7 +588,8 @@ func (app *App) run(done <-chan os.Signal) (exitCode int) {
}

sig := <-done
app.log().LogEvent(&fxevent.Stopping{Signal: sig})
app.log().LogEvent(&fxevent.Stopping{Signal: sig.Signal})
exitCode = sig.ExitCode

stopCtx, cancel := app.clock.WithTimeout(context.Background(), app.StopTimeout())
defer cancel()
Expand All @@ -597,7 +598,7 @@ func (app *App) run(done <-chan os.Signal) (exitCode int) {
return 1
}

return 0
return exitCode
}

// Err returns any error encountered during New's initialization. See the
Expand Down
5 changes: 2 additions & 3 deletions app_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ package fx
import (
"errors"
"fmt"
"os"
"sync"
"testing"

Expand All @@ -42,7 +41,7 @@ func TestAppRun(t *testing.T) {
app := New(
WithLogger(func() fxevent.Logger { return spy }),
)
done := make(chan os.Signal)
done := make(chan ShutdownSignal)

var wg sync.WaitGroup
wg.Add(1)
Expand All @@ -51,7 +50,7 @@ func TestAppRun(t *testing.T) {
app.run(done)
}()

done <- _sigINT
done <- ShutdownSignal{Signal: _sigINT}
wg.Wait()

assert.Equal(t, []string{
Expand Down
2 changes: 1 addition & 1 deletion docs/get-started/minimal.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ This application won't do anything yet except print a bunch of logs.

**What did we just do?**

We build an empty Fx application by calling `fx.New` with no arguments.
We built an empty Fx application by calling `fx.New` with no arguments.
Applications will normally pass arguments to `fx.New` to set up their
components.

Expand Down
6 changes: 6 additions & 0 deletions internal/e2e/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
This directory holds end-to-end tests for Fx.
Each subdirectory holds a complete Fx application
and a test for it.

This is marked as a separate Go module to prevent this code from being bundled
with the Fx library and allow for dependencies that don't leak into Fx.
21 changes: 21 additions & 0 deletions internal/e2e/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module go.uber.org/fx/internal/e2e

go 1.20

require (
github.com/stretchr/testify v1.8.2
go.uber.org/fx v1.19.2
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/dig v1.16.1 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.23.0 // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

replace go.uber.org/fx => ../..
31 changes: 31 additions & 0 deletions internal/e2e/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/dig v1.16.1 h1:+alNIBsl0qfY0j6epRubp/9obgtrObRAc5aD+6jbWY8=
go.uber.org/dig v1.16.1/go.mod h1:557JTAUZT5bUK0SvCwikmLPPtdQhfvLYtO5tJgQSbnk=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
34 changes: 34 additions & 0 deletions internal/e2e/shutdowner_run_exitcode/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) 2023 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package main

import (
"go.uber.org/fx"
)

func main() {
fx.New(
fx.Invoke(func(shutdowner fx.Shutdowner) error {
shutdowner.Shutdown(fx.ExitCode(20))
return nil
}),
).Run()
}
Loading

0 comments on commit 9c1a87d

Please sign in to comment.