I wrote this test a few months back and it was running successfully without any error and never went through init() function as I have only invoked handler function from test but now it's failing with below error:
/usr/local/opt/go/libexec/bin/go tool test2json -t /private/var/folders/wt/fc27nzn51rdbvwvjzkl05hlc0000gs/T/GoLand/___TestHandleRequest_in_next_api_cmd_getAllRawTransportOrders.test -test.v -test.paniconexit0 -test.run ^\QTestHandleRequest\E$
{"level":"fatal","msg":"no configuration found: not set","time":"2023-08-27T22:48:03+05:30"}
Process finished with the exit code 1
and I know that test is invoking init() function but then why it wasn't earlier. Am I missing something to understand here?
init.go
//go:build !test
// +build !test
package main
import (
"crypto/tls"
"encoding/json"
log "github.com/sirupsen/logrus"
"os"
"lib/storage/ssm"
"next-api/aws/dynamodb"
"next-api/cmd/utils"
"next-api/config"
"next-api/http"
)
func init() {
// Log as JSON instead of the default ASCII formatter.
log.SetFormatter(&log.JSONFormatter{})
// Output to stdout instead of the default stderr
// Can be any io.Writer, see below for File example
log.SetOutput(os.Stdout)
// Only log the warning severity or above.
log.SetLevel(log.InfoLevel)
var err error
paramsRepo := ssm.NewRepository()
configID, err := utils.GetEnv("CONFIG_ID")
if err != nil {
log.Fatal("no configuration found: ", err)
}
cfg, err = config.Load(configID, paramsRepo)
if err != nil {
log.Fatal("could not load config: ", err)
}
urls := http.URLs{}
json.Unmarshal([]byte(cfg.MABES.URLs), &urls)
// configure mTLS
cert, err := tls.X509KeyPair([]byte(cfg.MABES.Certificate), []byte(cfg.MABES.PrivateKey))
if err != nil {
log.Fatal("could not create MABES certificate: ", err)
}
MABES, err = http.NewMABESClient(urls, http.WithTLS(cert))
if err != nil {
log.Fatal("could not create sofaClient client.", err)
}
NEXT = dynamodb.NewRepository(cfg.NEXT.Table)
}
main.go
package main
import (
"encoding/json"
"fmt"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
log "github.com/sirupsen/logrus"
gohttp "net/http"
"next-api/api"
"next-api/config"
"next-api/errors"
"next-api/http"
"next-api/http/problem"
"next-api/mabes"
"next-api/next"
)
var (
cfg config.Config
MABES mabes.Client
NEXT next.Repository
)
func main() {
lambda.Start(handler)
}
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
facilityID := request.PathParameters["facilityID"]
if facilityID == "" {
return events.APIGatewayProxyResponse{
StatusCode: gohttp.StatusBadRequest,
Headers: http.Headers("application/problem+json"),
Body: problem.ServerError(fmt.Errorf("missing facilityID parameter")).ToJSONResponse(),
}, nil
}
transportOrders, err := api.GetAllRawTransportOrders(facilityID, request.QueryStringParameters, MABES, NEXT)
b, err := json.Marshal(transportOrders)
if err != nil {
log.Errorln(err)
if errors.Is(errors.NEXTRead, err) {
return events.APIGatewayProxyResponse{
StatusCode: gohttp.StatusOK,
Headers: http.Headers("application/json"),
Body: fmt.Sprintf(`{"data":%s}`, string(b)),
}, nil
}
return events.APIGatewayProxyResponse{
StatusCode: gohttp.StatusInternalServerError,
Headers: http.Headers("application/problem+json"),
Body: problem.ServerError(err).ToJSONResponse(),
}, nil
}
return events.APIGatewayProxyResponse{
StatusCode: gohttp.StatusOK,
Headers: http.Headers("application/json"),
Body: fmt.Sprintf(`{"data":%s}`, string(b)),
}, nil
}
main_test.go
package main
import (
"github.com/aws/aws-lambda-go/events"
"github.com/stretchr/testify/assert"
"net/http"
"strings"
"testing"
"time"
"next-api/api"
"next-api/mabes"
"next-api/next"
)
func TestHandleRequest(t *testing.T) {
t.Run("should return the TransportOrders", func(t *testing.T) {
req := events.APIGatewayProxyRequest{
PathParameters: map[string]string{
"facility": "11",
},
}
timeStamp, _ := time.Parse(time.RFC3339, time.Now().Format(time.RFC3339))
sofa1 := next.SofaTransferModel{}
sofa1.Phase = "1"
sofa1.PartKey.PartCode = "abcd"
sofa1.PartKey.DispatcherFacility = "11"
sofa1.PartKey.UsageCode = "01"
sofa1.Storage.Number = "00315"
sofa1.Shipment.RequestedArrivalDate = timeStamp.String()
transportOrders := make([]next.SofaTransferModel, 0)
transportOrders = append(transportOrders, sofa1)
getAllRawTransportOrdersCalls := 0
api.GetAllRawTransportOrders = func(facilityID string, params map[string]string, MABES mabes.Client, NEXT next.Repository) (next.SofaTransferObjects, error) {
getAllRawTransportOrdersCalls++
return transportOrders, nil
}
// when
res, err := handler(req)
// then
assert.Equal(t, 1, getAllRawTransportOrdersCalls)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
assert.True(t, strings.Contains(res.Body, transportOrders[0].PartKey.PartCode))
assert.True(t, strings.Contains(res.Body, transportOrders[0].Storage.Number))
})
}
Top level functions named init
(all lowercase) are always, and always have been, executed before the test. The reason init
fails now, even though it didn't before, it would appear, is a change in the environment; i.e. before CONFIG_ID
was set, but now it isn't, at least not in the shell in which the test is being executed.
https://go.dev/ref/spec#Package_initialization
The entire package is initialized by assigning initial values to all its package-level variables followed by calling all
init
functions in the order they appear in the source, possibly in multiple files, as presented to the compiler.
If you run the go test
command with -tags test
the build constraints at the top of the init.go
file, i.e. //go:build !test
, will be respected and the file will be omitted from the test build. But by default, there is no "test" build tag and therefore without the -tags test
argument those build constraints will be ignored and the init.go
file will be included in the test build.