or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cache-messaging.mdcloud-services.mdcompose.mdcore-containers.mddatabase-containers.mdindex.mdsearch-analytics.mdwaiting-strategies.mdweb-testing.md

compose.mddocs/

0

# Docker Compose Orchestration

1

2

Complete Docker Compose integration for managing multi-container environments, service discovery, and complex application stacks during testing. Enables full orchestration of interconnected services with configuration management and lifecycle control.

3

4

## Capabilities

5

6

### Compose Environment Management

7

8

Manage entire Docker Compose environments with automatic service startup, configuration loading, and coordinated shutdown.

9

10

```python { .api }

11

@dataclass

12

class DockerCompose:

13

context: Union[str, PathLike[str]]

14

compose_file_name: Optional[Union[str, list[str]]] = None

15

pull: bool = False

16

build: bool = False

17

wait: bool = True

18

keep_volumes: bool = False

19

env_file: Optional[str] = None

20

services: Optional[list[str]] = None

21

docker_command_path: Optional[str] = None

22

profiles: Optional[list[str]] = None

23

"""

24

Initialize Docker Compose environment.

25

26

Args:

27

context: Path to compose context directory

28

compose_file_name: Compose file name (default: docker-compose.yml)

29

pull: Pull images before starting

30

build: Build images before starting

31

wait: Wait for services to be ready

32

keep_volumes: Preserve volumes on shutdown

33

env_file: Environment file path

34

services: Specific services to run

35

docker_command_path: Custom docker-compose command path

36

profiles: Compose profiles to activate

37

**kwargs: Additional compose options

38

"""

39

40

def start(self) -> "DockerCompose":

41

"""

42

Start the compose environment.

43

44

Returns:

45

Self for method chaining

46

"""

47

48

def stop(self, down: bool = True) -> None:

49

"""

50

Stop the compose environment.

51

52

Args:

53

down: Use 'docker-compose down' instead of 'stop'

54

"""

55

56

def __enter__(self) -> "DockerCompose":

57

"""Context manager entry - starts compose environment."""

58

59

def __exit__(self, exc_type, exc_val, exc_tb) -> None:

60

"""Context manager exit - stops compose environment."""

61

```

62

63

### Service Discovery and Access

64

65

Access individual services within the compose environment, retrieve connection information, and interact with running containers.

66

67

```python { .api }

68

def get_container(self, service_name: Optional[str] = None, include_all: bool = False) -> ComposeContainer:

69

"""

70

Get container for specific service.

71

72

Args:

73

service_name: Service name (first service if None)

74

include_all: Include stopped containers

75

76

Returns:

77

ComposeContainer instance

78

"""

79

80

def get_containers(self, include_all: bool = False) -> list[ComposeContainer]:

81

"""

82

Get all containers in the compose environment.

83

84

Args:

85

include_all: Include stopped containers

86

87

Returns:

88

List of ComposeContainer instances

89

"""

90

91

def get_service_host(self, service_name: Optional[str] = None, port: Optional[int] = None) -> str:

92

"""

93

Get host address for service.

94

95

Args:

96

service_name: Service name

97

port: Service port

98

99

Returns:

100

Host address string

101

"""

102

103

def get_service_port(self, service_name: Optional[str] = None, port: Optional[int] = None) -> int:

104

"""

105

Get mapped port for service.

106

107

Args:

108

service_name: Service name

109

port: Internal service port

110

111

Returns:

112

Mapped host port number

113

"""

114

115

def get_service_host_and_port(self, service_name: Optional[str] = None, port: Optional[int] = None) -> tuple[str, int]:

116

"""

117

Get host and port for service.

118

119

Args:

120

service_name: Service name

121

port: Internal service port

122

123

Returns:

124

Tuple of (host, port)

125

"""

126

```

127

128

### Container Operations

129

130

Execute commands in running services, retrieve logs, and interact with the compose environment.

131

132

```python { .api }

133

def exec_in_container(self, command: str, service_name: Optional[str] = None) -> str:

134

"""

135

Execute command in service container.

136

137

Args:

138

command: Command to execute

139

service_name: Target service name

140

141

Returns:

142

Command output string

143

"""

144

145

def get_logs(self, *services: str) -> str:

146

"""

147

Get logs from services.

148

149

Args:

150

*services: Service names (all services if none specified)

151

152

Returns:

153

Combined log output string

154

"""

155

156

def get_config(

157

self,

158

path_resolution: bool = True,

159

normalize: bool = True,

160

interpolate: bool = True

161

) -> dict:

162

"""

163

Get compose configuration.

164

165

Args:

166

path_resolution: Resolve file paths

167

normalize: Normalize configuration format

168

interpolate: Interpolate environment variables

169

170

Returns:

171

Compose configuration dictionary

172

"""

173

```

174

175

### Service Health Checking

176

177

Wait for services to become available and ready for connections.

178

179

```python { .api }

180

def wait_for(self, url: str) -> None:

181

"""

182

Wait for URL to become available.

183

184

Args:

185

url: URL to check for availability

186

"""

187

```

188

189

### Container Information

190

191

Access detailed information about individual containers within the compose environment.

192

193

```python { .api }

194

class ComposeContainer:

195

ID: str # Container ID

196

Name: str # Container name

197

Command: str # Container command

198

Project: str # Compose project name

199

Service: str # Service name

200

State: str # Container state

201

Health: str # Health status

202

ExitCode: int # Exit code

203

Publishers: list[PublishedPortModel] # Published ports

204

205

def get_publisher(

206

self,

207

by_port: Optional[int] = None,

208

by_host: Optional[str] = None,

209

prefer_ip_version: str = "IPv4"

210

) -> PublishedPortModel:

211

"""

212

Get port publisher information.

213

214

Args:

215

by_port: Filter by port number

216

by_host: Filter by host address

217

prefer_ip_version: Preferred IP version ("IPv4" or "IPv6")

218

219

Returns:

220

PublishedPortModel instance

221

"""

222

223

class PublishedPortModel:

224

URL: str # Published URL

225

TargetPort: int # Target container port

226

PublishedPort: int # Published host port

227

Protocol: str # Protocol (tcp/udp)

228

229

def normalize(self) -> "PublishedPortModel":

230

"""

231

Normalize for Windows compatibility.

232

233

Returns:

234

Normalized PublishedPortModel

235

"""

236

```

237

238

## Usage Examples

239

240

### Basic Compose Usage

241

242

```python

243

from testcontainers.compose import DockerCompose

244

import requests

245

246

# docker-compose.yml in current directory with web and db services

247

with DockerCompose(".") as compose:

248

# Get service endpoints

249

web_host = compose.get_service_host("web", 80)

250

web_port = compose.get_service_port("web", 80)

251

252

# Make request to web service

253

response = requests.get(f"http://{web_host}:{web_port}/health")

254

assert response.status_code == 200

255

256

# Get database connection info

257

db_host = compose.get_service_host("db", 5432)

258

db_port = compose.get_service_port("db", 5432)

259

print(f"Database available at {db_host}:{db_port}")

260

```

261

262

### Custom Compose File

263

264

```python

265

from testcontainers.compose import DockerCompose

266

267

# Use specific compose file and environment

268

compose = DockerCompose(

269

context="./docker",

270

compose_file_name="docker-compose.test.yml",

271

pull=True, # Pull latest images

272

build=True, # Build custom images

273

env_file="test.env"

274

)

275

276

with compose:

277

# Execute command in service

278

result = compose.exec_in_container("ls -la", service_name="app")

279

print(f"Container contents: {result}")

280

281

# Get logs from specific services

282

logs = compose.get_logs("app", "worker")

283

print(f"Service logs: {logs}")

284

```

285

286

### Service-Specific Operations

287

288

```python

289

from testcontainers.compose import DockerCompose

290

291

with DockerCompose(".", compose_file_name="microservices.yml") as compose:

292

# Get all running containers

293

containers = compose.get_containers()

294

295

for container in containers:

296

print(f"Service: {container.Service}")

297

print(f"State: {container.State}")

298

print(f"Health: {container.Health}")

299

300

# Get port information

301

for publisher in container.Publishers:

302

print(f"Port {publisher.TargetPort} -> {publisher.PublishedPort}")

303

304

# Access specific service container

305

api_container = compose.get_container("api")

306

print(f"API container ID: {api_container.ID}")

307

```

308

309

### Profile-Based Deployment

310

311

```python

312

from testcontainers.compose import DockerCompose

313

314

# Use compose profiles for different environments

315

test_compose = DockerCompose(

316

context=".",

317

profiles=["test", "monitoring"],

318

services=["app", "db", "redis"] # Only start specific services

319

)

320

321

with test_compose:

322

# Only services in 'test' and 'monitoring' profiles are started

323

app_url = f"http://{test_compose.get_service_host('app', 8080)}:{test_compose.get_service_port('app', 8080)}"

324

print(f"Test app available at: {app_url}")

325

```

326

327

### Integration Testing Setup

328

329

```python

330

from testcontainers.compose import DockerCompose

331

import pytest

332

import requests

333

334

@pytest.fixture(scope="session")

335

def app_stack():

336

"""Pytest fixture for full application stack."""

337

with DockerCompose(".", compose_file_name="test-stack.yml") as compose:

338

# Wait for services to be ready

339

compose.wait_for(f"http://{compose.get_service_host('app', 8080)}:{compose.get_service_port('app', 8080)}/health")

340

341

yield compose

342

343

def test_api_endpoints(app_stack):

344

"""Test API endpoints with full stack."""

345

compose = app_stack

346

347

# Get API endpoint

348

api_host = compose.get_service_host("api", 3000)

349

api_port = compose.get_service_port("api", 3000)

350

base_url = f"http://{api_host}:{api_port}"

351

352

# Test endpoints

353

response = requests.get(f"{base_url}/users")

354

assert response.status_code == 200

355

356

response = requests.post(f"{base_url}/users", json={"name": "Test User"})

357

assert response.status_code == 201

358

359

def test_database_integration(app_stack):

360

"""Test database operations."""

361

compose = app_stack

362

363

# Execute database command

364

result = compose.exec_in_container("psql -U postgres -c 'SELECT version();'", "db")

365

assert "PostgreSQL" in result

366

```

367

368

### Complex Multi-Service Architecture

369

370

```python

371

from testcontainers.compose import DockerCompose

372

import time

373

374

# docker-compose.yml with web, api, worker, db, redis, elasticsearch

375

with DockerCompose(".", compose_file_name="full-stack.yml") as compose:

376

# Get all service endpoints

377

services = {

378

"web": compose.get_service_host_and_port("web", 80),

379

"api": compose.get_service_host_and_port("api", 3000),

380

"db": compose.get_service_host_and_port("db", 5432),

381

"redis": compose.get_service_host_and_port("redis", 6379),

382

"elasticsearch": compose.get_service_host_and_port("elasticsearch", 9200)

383

}

384

385

print("Service endpoints:")

386

for service, (host, port) in services.items():

387

print(f" {service}: {host}:{port}")

388

389

# Wait for all services to be healthy

390

for container in compose.get_containers():

391

while container.Health not in ["healthy", ""]:

392

print(f"Waiting for {container.Service} to be healthy...")

393

time.sleep(2)

394

# Refresh container info

395

container = compose.get_container(container.Service)

396

397

print("All services are ready!")

398

399

# Run integration tests

400

web_host, web_port = services["web"]

401

response = requests.get(f"http://{web_host}:{web_port}")

402

print(f"Web response status: {response.status_code}")

403

```

404

405

### Environment Configuration

406

407

```python

408

from testcontainers.compose import DockerCompose

409

import os

410

411

# Set environment variables for compose

412

os.environ["DATABASE_URL"] = "postgres://test:test@db:5432/testdb"

413

os.environ["REDIS_URL"] = "redis://redis:6379"

414

os.environ["DEBUG"] = "true"

415

416

# Compose with environment file and variable interpolation

417

compose = DockerCompose(

418

context="./infrastructure",

419

env_file="test.env",

420

keep_volumes=False # Clean up volumes after testing

421

)

422

423

with compose:

424

# Environment variables are available in compose services

425

config = compose.get_config()

426

print("Compose configuration:", config)

427

428

# Services use interpolated environment variables

429

app_logs = compose.get_logs("app")

430

print("Application logs:", app_logs)

431

```