Skip to content

Commit dccc54a

Browse files
committed
Merge branch 'main' into contract-repo
2 parents 6398c3c + 2390942 commit dccc54a

16 files changed

+313
-162
lines changed

.github/workflows/make.yml

+11-29
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ jobs:
1010
build:
1111
strategy:
1212
matrix:
13-
os: [ubuntu-latest, macos-latest]
14-
13+
os: [ubuntu-latest]
14+
1515
runs-on: ${{matrix.os}}
1616

1717
steps:
@@ -31,39 +31,21 @@ jobs:
3131
uses: actions/setup-go@v4
3232
with:
3333
go-version: '^1.22.5'
34-
34+
3535
- name: Go Tidy
3636
run: go mod tidy
37-
37+
3838
- name: Install dependencies
3939
run: |
4040
go mod download
4141
go install google.golang.org/protobuf/cmd/[email protected]
4242
go install google.golang.org/grpc/cmd/[email protected]
43-
44-
- name: setup env
45-
run:
46-
echo "$GOPATH/bin" >> $GITHUB_PATH
47-
48-
- name: Set BFF port from config
49-
run: |
50-
go run scripts/read_port.go >> $GITHUB_ENV
51-
52-
- name: Build with Makefile
53-
run: make all
54-
55-
- name: Set up Java
56-
uses: actions/setup-java@v4
43+
44+
- name: Setup Testcontainers Cloud Client
45+
uses: atomicjar/testcontainers-cloud-setup-action@v1
5746
with:
58-
distribution: 'temurin' # See 'Supported distributions' for available options
59-
java-version: '17'
60-
- run: java --version
61-
62-
- name: Start gRPC Stub
63-
run: java --version && java -jar lib/specmatic-grpc-0.0.4-TRIAL-all.jar stub &
64-
65-
- name: Start Golang gRPC Server
66-
run: ./specmatic-order-bff-grpc-go &
47+
token: ${{ secrets.TC_CLOUD_TOKEN }}
48+
wait: true
6749

68-
- name: Start gRPC Contract Test
69-
run: java -DSPECMATIC_GENERATIVE_TESTS=true -jar lib/specmatic-grpc-0.0.4-TRIAL-all.jar test --port ${{ env.BFF_SERVER_PORT }}
50+
- name: start dockerized tests
51+
run: go test contract_test.go -v -count=1

README.md

-54
Original file line numberDiff line numberDiff line change
@@ -30,57 +30,3 @@ git config submodule.recurse true
3030
go mod tidy
3131
go test contract_test.go -v -count=1
3232
```
33-
34-
### Contract Testing BFF by building and running the application using specmatic-grpc JAR file (old-school)
35-
36-
1. Installing pre-requisites
37-
38-
```shell
39-
go install google.golang.org/protobuf/cmd/[email protected]
40-
go install google.golang.org/grpc/cmd/[email protected]
41-
```
42-
1.1. Add protoc-gen-go to your path using the following command:
43-
44-
```shell
45-
echo 'export PATH=$PATH:$(go env GOPATH)/bin' >> ~/.bash_profile
46-
source ~/.bash_profile
47-
```
48-
49-
2. Installing the `buf` tool
50-
```shell
51-
brew install bufbuild/buf/buf
52-
```
53-
For more options to install buf tool, refer to [buf installation guide](https://docs.buf.build/installation)
54-
55-
3. Building the application
56-
57-
```shell
58-
go mod tidy
59-
go mod download
60-
make clean
61-
make all
62-
```
63-
64-
## Running Contract Tests
65-
66-
### Using specmatic-grpc JAR file
67-
68-
* Start Specmatic stub server -
69-
```shell
70-
java -jar lib/specmatic-grpc-0.0.4-TRIAL-all.jar stub
71-
```
72-
* Run the Go BFF app
73-
```shell
74-
./specmatic-order-bff-grpc-go
75-
```
76-
* Run contract tests (with API resiliency switched on)
77-
```shell
78-
java -DSPECMATIC_GENERATIVE_TESTS=true -jar lib/specmatic-grpc-0.0.4-TRIAL-all.jar test --port=8080
79-
```
80-
81-
## Debugging steps
82-
83-
In case of pb files already exists,
84-
```shell
85-
rm -rf ~/Library/Caches/buf
86-
```

cmd/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
)
1818

1919
func main() {
20-
cfg, err := config.LoadConfig("config.yaml")
20+
cfg, err := config.LoadConfig()
2121
if err != nil {
2222
log.Fatalf("Failed to load configuration: %v", err)
2323
}

config.yaml

-6
This file was deleted.

contract_test.go

+119-30
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,33 @@ import (
77
"io"
88
"log"
99
"os"
10-
"os/exec"
1110
"path/filepath"
1211
"specmatic-order-bff-grpc-go/internal/com/store/order/bff/config"
1312
"strconv"
1413
"testing"
14+
"time"
1515

1616
"github.com/docker/go-connections/nat"
17+
"github.com/stretchr/testify/require"
1718
"github.com/testcontainers/testcontainers-go"
19+
"github.com/testcontainers/testcontainers-go/network"
1820
"github.com/testcontainers/testcontainers-go/wait"
1921
)
2022

2123
type testEnvironment struct {
2224
ctx context.Context
2325
domainServiceContainer testcontainers.Container
2426
domainServiceDynamicPort string
27+
kafkaServiceContainer testcontainers.Container
28+
kafkaServiceDynamicPort string
2529
bffServiceContainer testcontainers.Container
2630
bffServiceDynamicPort string
31+
dockerNetwork *testcontainers.DockerNetwork
2732
config *config.Config
2833
}
2934

30-
func TestIntegration(t *testing.T) {
31-
env := setUpEnv(t)
35+
func TestContract(t *testing.T) {
36+
env := setUpEnv(t)
3237

3338
// setUp (start domain service stub with specmatic-grpc and bff server in container)
3439
setUp(t, env)
@@ -41,35 +46,51 @@ func TestIntegration(t *testing.T) {
4146
}
4247

4348
func setUpEnv(t *testing.T) *testEnvironment {
44-
config, err := config.LoadConfig("config.yaml")
45-
if err != nil {
46-
t.Fatalf("Failed to load config: %v", err)
47-
}
48-
49-
return &testEnvironment{
50-
ctx: context.Background(),
51-
config: config,
52-
}
49+
config, err := config.LoadConfig()
50+
if err != nil {
51+
t.Fatalf("Failed to load config: %v", err)
52+
}
53+
54+
return &testEnvironment{
55+
ctx: context.Background(),
56+
config: config,
57+
}
5358
}
5459

5560
func setUp(t *testing.T, env *testEnvironment) {
5661
var err error
5762

63+
// Create a sub net and store in env.
64+
newNetwork, err := network.New(env.ctx)
65+
if err != nil {
66+
t.Fatal(err)
67+
}
68+
t.Cleanup(func() {
69+
require.NoError(t, newNetwork.Remove(env.ctx))
70+
})
71+
env.dockerNetwork = newNetwork
72+
5873
printHeader(t, 1, "Starting Domain Service")
5974
env.domainServiceContainer, env.domainServiceDynamicPort, err = startDomainService(env)
6075
if err != nil {
61-
t.Fatalf("could not start domain service container: %v", err)
76+
t.Fatalf("could not start domain service container: %v", err)
77+
}
78+
79+
printHeader(t, 2, "Starting Kafka Service")
80+
env.kafkaServiceContainer, env.kafkaServiceDynamicPort, err = startKafkaMock(env)
81+
if err != nil {
82+
t.Fatalf("could not start domain service container: %v", err)
6283
}
6384

64-
printHeader(t, 2, "Starting BFF Service")
85+
printHeader(t, 3, "Starting BFF Service")
6586
env.bffServiceContainer, env.bffServiceDynamicPort, err = startBFFService(t, env)
6687
if err != nil {
67-
t.Fatalf("could not start bff service container: %v", err)
88+
t.Fatalf("could not start bff service container: %v", err)
6889
}
6990
}
7091

7192
func runTests(t *testing.T, env *testEnvironment) {
72-
printHeader(t, 3, "Starting tests")
93+
printHeader(t, 4, "Starting tests")
7394
testLogs, err := runTestContainer(env)
7495
if err != nil {
7596
t.Fatalf("Could not run test container: %s", err)
@@ -86,6 +107,11 @@ func tearDown(t *testing.T, env *testEnvironment) {
86107
t.Logf("Failed to terminate BFF container: %v", err)
87108
}
88109
}
110+
if env.kafkaServiceContainer != nil {
111+
if err := env.kafkaServiceContainer.Terminate(env.ctx); err != nil {
112+
t.Logf("Failed to terminate Kafka container: %v", err)
113+
}
114+
}
89115
if env.domainServiceContainer != nil {
90116
if err := env.domainServiceContainer.Terminate(env.ctx); err != nil {
91117
t.Logf("Failed to terminate stub container: %v", err)
@@ -111,6 +137,12 @@ func startDomainService(env *testEnvironment) (testcontainers.Container, string,
111137
Mounts: testcontainers.Mounts(
112138
testcontainers.BindMount(filepath.Join(pwd, "specmatic.yaml"), "/usr/src/app/specmatic.yaml"),
113139
),
140+
Networks: []string{
141+
env.dockerNetwork.Name,
142+
},
143+
NetworkAliases: map[string][]string{
144+
env.dockerNetwork.Name: {"order-api-mock"},
145+
},
114146
WaitingFor: wait.ForLog("Stub server is running"),
115147
}
116148

@@ -130,33 +162,86 @@ func startDomainService(env *testEnvironment) (testcontainers.Container, string,
130162
return stubContainer, domainServicePort.Port(), nil
131163
}
132164

133-
func startBFFService(t *testing.T, env *testEnvironment) (testcontainers.Container, string, error) {
134-
dockerfilePath := "Dockerfile"
165+
func startKafkaMock(env *testEnvironment) (testcontainers.Container, string, error) {
166+
pwd, err := os.Getwd()
167+
if err != nil {
168+
return nil, "", fmt.Errorf("Error getting current directory: %v", err)
135169

136-
bffImageName := "specmatic-order-bff-grpc-go"
137-
buildCmd := exec.Command("docker", "build", "-t", bffImageName, "-f", dockerfilePath, ".")
170+
}
138171

139-
if err := buildCmd.Run(); err != nil {
140-
return nil, "", fmt.Errorf("could not build BFF image: %w", err)
172+
port, err := nat.NewPort("tcp", env.config.KafkaService.Port)
173+
if err != nil {
174+
return nil, "", fmt.Errorf("invalid port number: %w", err)
141175
}
142176

177+
req := testcontainers.ContainerRequest{
178+
Name: "specmatic-kafka",
179+
Image: "znsio/specmatic-kafka-trial:0.22.5",
180+
ExposedPorts: []string{port.Port() + "/tcp"},
181+
Networks: []string{
182+
env.dockerNetwork.Name,
183+
},
184+
NetworkAliases: map[string][]string{
185+
env.dockerNetwork.Name: {"specmatic-kafka"},
186+
},
187+
Env: map[string]string{
188+
"KAFKA_EXTERNAL_HOST": env.config.KafkaService.Host,
189+
"KAFKA_EXTERNAL_PORT": port.Port(),
190+
},
191+
Cmd: []string{"--config=/specmatic.json"}, // TODO: Switch to YAML
192+
Mounts: testcontainers.Mounts(
193+
testcontainers.BindMount(filepath.Join(pwd, "specmatic.json"), "/specmatic.json"),
194+
),
195+
WaitingFor: wait.ForLog("Listening on topics: (product-queries)").WithStartupTimeout(2 * time.Minute),
196+
}
197+
198+
kafkaC, err := testcontainers.GenericContainer(env.ctx, testcontainers.GenericContainerRequest{
199+
ContainerRequest: req,
200+
Started: true,
201+
})
202+
if err != nil {
203+
fmt.Printf("Error starting Kafka mock container: %v", err)
204+
}
205+
206+
mappedPort, err := kafkaC.MappedPort(env.ctx, port)
207+
if err != nil {
208+
fmt.Printf("Error getting mapped port for Kafka mock: %v", err)
209+
}
210+
211+
return kafkaC, mappedPort.Port(), nil
212+
}
213+
214+
func startBFFService(t *testing.T, env *testEnvironment) (testcontainers.Container, string, error) {
215+
143216
port, err := nat.NewPort("tcp", env.config.BFFServer.Port)
144217
if err != nil {
145218
return nil, "", fmt.Errorf("invalid port number: %w", err)
146219
}
147220

221+
dockerfilePath := "Dockerfile"
222+
contextPath := "."
223+
148224
req := testcontainers.ContainerRequest{
149-
Image: bffImageName,
225+
FromDockerfile: testcontainers.FromDockerfile{
226+
Context: contextPath,
227+
Dockerfile: dockerfilePath,
228+
},
150229
Env: map[string]string{
151-
"DOMAIN_SERVER_PORT": env.domainServiceDynamicPort,
152-
"DOMAIN_SERVER_HOST": "host.docker.internal",
230+
"DOMAIN_SERVER_PORT": env.config.Backend.Port,
231+
"DOMAIN_SERVER_HOST": "order-api-mock",
232+
"KAFKA_PORT": env.config.KafkaService.Port,
233+
"KAFKA_HOST": "specmatic-kafka",
153234
},
154-
ExposedPorts: []string{port.Port() + "/tcp"},
235+
Networks: []string{
236+
env.dockerNetwork.Name,
237+
},
238+
NetworkAliases: map[string][]string{
239+
env.dockerNetwork.Name: {"bff-service"},
240+
},
241+
ExposedPorts: []string{env.config.BFFServer.Port + "/tcp"},
155242
WaitingFor: wait.ForLog("Starting gRPC server"),
156243
}
157244

158-
t.Log("Container created")
159-
160245
bffContainer, err := testcontainers.GenericContainer(env.ctx, testcontainers.GenericContainerRequest{
161246
ContainerRequest: req,
162247
Started: true,
@@ -179,7 +264,8 @@ func runTestContainer(env *testEnvironment) (string, error) {
179264
log.Fatalf("Error getting current directory: %v", err)
180265
}
181266

182-
bffPortInt, err := strconv.Atoi(env.bffServiceDynamicPort)
267+
bffPortInt, err := strconv.Atoi(env.config.BFFServer.Port)
268+
// bffPortInt, err := strconv.Atoi(env.bffServiceDynamicPort)
183269
if err != nil {
184270
return "", fmt.Errorf("invalid port number: %w", err)
185271
}
@@ -189,10 +275,13 @@ func runTestContainer(env *testEnvironment) (string, error) {
189275
Env: map[string]string{
190276
"SPECMATIC_GENERATIVE_TESTS": "true",
191277
},
192-
Cmd: []string{"test", fmt.Sprintf("--port=%d", bffPortInt), "--host=host.docker.internal"},
278+
Cmd: []string{"test", fmt.Sprintf("--port=%d", bffPortInt), "--host=bff-service"},
193279
Mounts: testcontainers.Mounts(
194280
testcontainers.BindMount(filepath.Join(pwd, "specmatic.yaml"), "/usr/src/app/specmatic.yaml"),
195281
),
282+
Networks: []string{
283+
env.dockerNetwork.Name,
284+
},
196285
WaitingFor: wait.ForLog("Passed Tests:"),
197286
}
198287

0 commit comments

Comments
 (0)