or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

attribute-extraction.mdcrud-handlers.mdcrud-operations.mdcustom-resources.mdindex.mdjunit-integration.mdmock-server-management.mdwebsocket-operations.md

crud-operations.mddocs/

0

# CRUD Operations

1

2

Full in-memory Kubernetes API implementation supporting all standard CRUD operations, resource watching, and advanced features like patches and finalizers.

3

4

## Capabilities

5

6

### KubernetesCrudDispatcher

7

8

Main CRUD dispatcher providing full in-memory Kubernetes API functionality.

9

10

```java { .api }

11

/**

12

* CRUD-mode dispatcher providing full in-memory Kubernetes API

13

* Stores resources in memory and handles all standard Kubernetes operations

14

*/

15

public class KubernetesCrudDispatcher extends CrudDispatcher

16

implements KubernetesCrudPersistence, CustomResourceAware {

17

18

/**

19

* Default constructor with empty custom resource list

20

*/

21

public KubernetesCrudDispatcher();

22

23

/**

24

* Constructor with initial custom resource definitions

25

* @param crdContexts List of custom resource definition contexts

26

*/

27

public KubernetesCrudDispatcher(List<CustomResourceDefinitionContext> crdContexts);

28

}

29

```

30

31

### Create Operations

32

33

Handle HTTP POST requests for resource creation with proper validation and storage.

34

35

```java { .api }

36

/**

37

* Handle resource creation requests

38

* Validates resources and stores them with generated resource versions

39

* @param request RecordedRequest containing resource data

40

* @return MockResponse with created resource or error

41

*/

42

public MockResponse handleCreate(RecordedRequest request);

43

```

44

45

**Supported Features:**

46

- Resource validation and schema checking

47

- Automatic metadata generation (resource version, creation timestamp)

48

- Namespace validation and defaulting

49

- Name generation for resources without names

50

- Conflict detection for duplicate resources

51

- Custom resource creation support

52

53

**Usage Examples:**

54

55

```java

56

@EnableKubernetesMockClient(crud = true)

57

class CreateOperationsTest {

58

KubernetesClient client;

59

60

@Test

61

void testPodCreation() {

62

// Create a pod

63

Pod pod = new PodBuilder()

64

.withNewMetadata()

65

.withName("test-pod")

66

.withNamespace("default")

67

.endMetadata()

68

.withNewSpec()

69

.addNewContainer()

70

.withName("app")

71

.withImage("nginx")

72

.endContainer()

73

.endSpec()

74

.build();

75

76

Pod created = client.pods().inNamespace("default").resource(pod).create();

77

78

assertNotNull(created.getMetadata().getResourceVersion());

79

assertNotNull(created.getMetadata().getCreationTimestamp());

80

assertEquals("test-pod", created.getMetadata().getName());

81

}

82

83

@Test

84

void testGeneratedNameCreation() {

85

// Create pod with generateName

86

Pod pod = new PodBuilder()

87

.withNewMetadata()

88

.withGenerateName("test-pod-")

89

.withNamespace("default")

90

.endMetadata()

91

.build();

92

93

Pod created = client.pods().inNamespace("default").resource(pod).create();

94

95

assertTrue(created.getMetadata().getName().startsWith("test-pod-"));

96

}

97

}

98

```

99

100

### Read Operations

101

102

Handle HTTP GET requests for retrieving individual resources and resource lists.

103

104

```java { .api }

105

/**

106

* Handle resource retrieval requests

107

* Supports both individual resource GET and list operations

108

* @param path Request path identifying the resource(s)

109

* @return MockResponse with resource data or 404 if not found

110

*/

111

public MockResponse handleGet(String path);

112

```

113

114

**Supported Features:**

115

- Individual resource retrieval by name

116

- Resource list operations with label and field selectors

117

- Namespace-scoped and cluster-scoped resources

118

- API discovery endpoints (e.g., `/api/v1`, `/apis/apps/v1`)

119

- Resource metadata endpoints

120

- Pagination support with continue tokens

121

122

**Usage Examples:**

123

124

```java

125

@Test

126

void testResourceRetrieval() {

127

// Create a resource first

128

Pod pod = client.pods().inNamespace("default")

129

.resource(new PodBuilder().withNewMetadata().withName("test").endMetadata().build())

130

.create();

131

132

// Retrieve by name

133

Pod retrieved = client.pods().inNamespace("default").withName("test").get();

134

assertEquals("test", retrieved.getMetadata().getName());

135

136

// List all pods

137

PodList list = client.pods().inNamespace("default").list();

138

assertEquals(1, list.getItems().size());

139

140

// List with label selector

141

client.pods().inNamespace("default").withLabel("app", "web").list();

142

}

143

144

@Test

145

void testApiDiscovery() {

146

// API discovery works automatically

147

APIResourceList v1Resources = client.getKubernetesVersion();

148

assertNotNull(v1Resources);

149

}

150

```

151

152

### Update Operations

153

154

Handle HTTP PUT requests for full resource updates with optimistic concurrency control.

155

156

```java { .api }

157

/**

158

* Handle resource update requests

159

* Performs full resource replacement with resource version checking

160

* @param request RecordedRequest containing updated resource data

161

* @return MockResponse with updated resource or conflict error

162

*/

163

public MockResponse handleUpdate(RecordedRequest request);

164

```

165

166

**Supported Features:**

167

- Full resource replacement

168

- Resource version conflict detection

169

- Metadata preservation and updates

170

- Status subresource updates

171

- Scale subresource updates

172

- Custom resource updates

173

174

**Usage Examples:**

175

176

```java

177

@Test

178

void testResourceUpdate() {

179

// Create initial resource

180

Pod pod = client.pods().inNamespace("default")

181

.resource(new PodBuilder().withNewMetadata().withName("test").endMetadata().build())

182

.create();

183

184

// Update the resource

185

pod.getMetadata().getLabels().put("updated", "true");

186

Pod updated = client.pods().inNamespace("default").resource(pod).update();

187

188

assertEquals("true", updated.getMetadata().getLabels().get("updated"));

189

assertNotEquals(pod.getMetadata().getResourceVersion(),

190

updated.getMetadata().getResourceVersion());

191

}

192

193

@Test

194

void testOptimisticConcurrency() {

195

Pod pod = client.pods().inNamespace("default")

196

.resource(new PodBuilder().withNewMetadata().withName("test").endMetadata().build())

197

.create();

198

199

// Simulate concurrent modification

200

pod.getMetadata().setResourceVersion("999"); // Invalid version

201

202

assertThrows(KubernetesClientException.class, () -> {

203

client.pods().inNamespace("default").resource(pod).update();

204

});

205

}

206

```

207

208

### Patch Operations

209

210

Handle HTTP PATCH requests supporting JSON Patch, Strategic Merge Patch, and JSON Merge Patch.

211

212

```java { .api }

213

/**

214

* Handle resource patch requests

215

* Supports multiple patch formats and partial updates

216

* @param request RecordedRequest containing patch data and content type

217

* @return MockResponse with patched resource or error

218

*/

219

public MockResponse handlePatch(RecordedRequest request);

220

```

221

222

**Supported Patch Types:**

223

- JSON Patch (RFC 6902)

224

- Strategic Merge Patch (Kubernetes-specific)

225

- JSON Merge Patch (RFC 7396)

226

- Server-side Apply patches

227

228

**Usage Examples:**

229

230

```java

231

@Test

232

void testStrategicMergePatch() {

233

// Create pod with initial labels

234

Pod pod = client.pods().inNamespace("default")

235

.resource(new PodBuilder()

236

.withNewMetadata()

237

.withName("test")

238

.addToLabels("env", "dev")

239

.endMetadata()

240

.build())

241

.create();

242

243

// Strategic merge patch to add label

244

Pod patch = new PodBuilder()

245

.withNewMetadata()

246

.withName("test")

247

.addToLabels("app", "web")

248

.endMetadata()

249

.build();

250

251

Pod patched = client.pods().inNamespace("default")

252

.withName("test").patch(PatchContext.of(PatchType.STRATEGIC_MERGE), patch);

253

254

// Both labels should be present

255

assertEquals("dev", patched.getMetadata().getLabels().get("env"));

256

assertEquals("web", patched.getMetadata().getLabels().get("app"));

257

}

258

259

@Test

260

void testJsonPatch() {

261

Pod pod = client.pods().inNamespace("default")

262

.resource(new PodBuilder().withNewMetadata().withName("test").endMetadata().build())

263

.create();

264

265

// JSON Patch operations

266

String jsonPatch = "[{\"op\":\"add\",\"path\":\"/metadata/labels\",\"value\":{\"patched\":\"true\"}}]";

267

268

Pod patched = client.pods().inNamespace("default")

269

.withName("test").patch(PatchContext.of(PatchType.JSON), jsonPatch);

270

271

assertEquals("true", patched.getMetadata().getLabels().get("patched"));

272

}

273

```

274

275

### Delete Operations

276

277

Handle HTTP DELETE requests with proper finalizer handling and cascading deletion.

278

279

```java { .api }

280

/**

281

* Handle resource deletion requests

282

* Supports finalizers, graceful deletion, and cascading options

283

* @param path Request path identifying the resource to delete

284

* @return MockResponse with deletion confirmation or resource with deletion timestamp

285

*/

286

public MockResponse handleDelete(String path);

287

```

288

289

**Supported Features:**

290

- Immediate deletion for resources without finalizers

291

- Finalizer-based deletion workflow

292

- Graceful deletion periods

293

- Cascade deletion options

294

- Bulk deletion with label selectors

295

296

**Usage Examples:**

297

298

```java

299

@Test

300

void testImmediateDeletion() {

301

Pod pod = client.pods().inNamespace("default")

302

.resource(new PodBuilder().withNewMetadata().withName("test").endMetadata().build())

303

.create();

304

305

// Delete without finalizers - immediate removal

306

client.pods().inNamespace("default").withName("test").delete();

307

308

Pod deleted = client.pods().inNamespace("default").withName("test").get();

309

assertNull(deleted);

310

}

311

312

@Test

313

void testFinalizerDeletion() {

314

// Create resource with finalizer

315

Pod pod = new PodBuilder()

316

.withNewMetadata()

317

.withName("test")

318

.addToFinalizers("example.com/my-finalizer")

319

.endMetadata()

320

.build();

321

client.pods().inNamespace("default").resource(pod).create();

322

323

// Delete - should mark for deletion but not remove

324

client.pods().inNamespace("default").withName("test").delete();

325

326

Pod marked = client.pods().inNamespace("default").withName("test").get();

327

assertNotNull(marked.getMetadata().getDeletionTimestamp());

328

329

// Remove finalizer to complete deletion

330

marked.getMetadata().getFinalizers().clear();

331

client.pods().inNamespace("default").resource(marked).update();

332

333

// Now it should be gone

334

Pod gone = client.pods().inNamespace("default").withName("test").get();

335

assertNull(gone);

336

}

337

```

338

339

### Watch Operations

340

341

Handle WebSocket watch requests for real-time resource change notifications.

342

343

```java { .api }

344

/**

345

* Handle watch requests for real-time resource monitoring

346

* Establishes WebSocket connection and sends watch events

347

* @param path Request path with watch=true parameter

348

* @return MockResponse with WebSocket upgrade for watch stream

349

*/

350

public MockResponse handleWatch(String path);

351

```

352

353

**Supported Features:**

354

- Resource-specific watches

355

- Namespace-scoped and cluster-scoped watches

356

- Label and field selector filtering

357

- Resume from resource version

358

- Watch event types: ADDED, MODIFIED, DELETED

359

360

**Usage Examples:**

361

362

```java

363

@Test

364

void testResourceWatch() throws InterruptedException {

365

CountDownLatch latch = new CountDownLatch(2);

366

List<WatchEvent<Pod>> events = new ArrayList<>();

367

368

// Start watching pods

369

Watch watch = client.pods().inNamespace("default").watch(new Watcher<Pod>() {

370

@Override

371

public void eventReceived(Action action, Pod resource) {

372

events.add(new WatchEvent<>(action, resource));

373

latch.countDown();

374

}

375

376

@Override

377

public void onClose(WatcherException cause) {}

378

});

379

380

try {

381

// Create a pod - should trigger ADDED event

382

Pod pod = new PodBuilder().withNewMetadata().withName("watched").endMetadata().build();

383

client.pods().inNamespace("default").resource(pod).create();

384

385

// Update the pod - should trigger MODIFIED event

386

pod.getMetadata().getLabels().put("updated", "true");

387

client.pods().inNamespace("default").resource(pod).update();

388

389

// Wait for events

390

assertTrue(latch.await(5, TimeUnit.SECONDS));

391

assertEquals(2, events.size());

392

assertEquals(Watcher.Action.ADDED, events.get(0).getAction());

393

assertEquals(Watcher.Action.MODIFIED, events.get(1).getAction());

394

} finally {

395

watch.close();

396

}

397

}

398

```

399

400

### Mixed Mode Dispatcher

401

402

Combines expectations-based mocking with CRUD operations for flexible testing.

403

404

```java { .api }

405

/**

406

* Composite dispatcher combining MockDispatcher and KubernetesCrudDispatcher

407

* Pre-recorded expectations take priority over CRUD operations

408

*/

409

public class KubernetesMixedDispatcher extends Dispatcher

410

implements Resetable, CustomResourceAware {

411

412

/**

413

* Constructor with responses map for expectations

414

* @param responses Map of request-response expectations

415

*/

416

public KubernetesMixedDispatcher(Map<ServerRequest, Queue<ServerResponse>> responses);

417

418

/**

419

* Constructor with custom resource contexts

420

* @param responses Map of request-response expectations

421

* @param crdContexts List of custom resource definition contexts

422

*/

423

public KubernetesMixedDispatcher(

424

Map<ServerRequest, Queue<ServerResponse>> responses,

425

List<CustomResourceDefinitionContext> crdContexts);

426

427

/**

428

* Dispatch requests to appropriate handler

429

* Checks expectations first, falls back to CRUD operations

430

* @param request RecordedRequest to handle

431

* @return MockResponse from expectations or CRUD handler

432

*/

433

public MockResponse dispatch(RecordedRequest request);

434

}

435

```

436

437

**Usage Examples:**

438

439

```java

440

@EnableKubernetesMockClient(crud = true)

441

class MixedModeTest {

442

KubernetesMockServer server;

443

KubernetesClient client;

444

445

@Test

446

void testMixedMode() {

447

// Set up specific expectation

448

server.expect().get()

449

.withPath("/api/v1/namespaces/kube-system/pods/special-pod")

450

.andReturn(200, new PodBuilder()

451

.withNewMetadata().withName("special-pod").endMetadata()

452

.build())

453

.once();

454

455

// This uses the expectation

456

Pod special = client.pods().inNamespace("kube-system").withName("special-pod").get();

457

assertEquals("special-pod", special.getMetadata().getName());

458

459

// This uses CRUD mode (no expectation set)

460

Pod regular = new PodBuilder().withNewMetadata().withName("regular").endMetadata().build();

461

client.pods().inNamespace("default").resource(regular).create();

462

463

Pod retrieved = client.pods().inNamespace("default").withName("regular").get();

464

assertEquals("regular", retrieved.getMetadata().getName());

465

}

466

}

467

```