@flisk-sh/flisk 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +305 -52
- package/cli/dist/commands/doctor.js +62 -0
- package/cli/dist/commands/runtime.js +6 -3
- package/cli/dist/generator/template-engine.js +7 -4
- package/cli/dist/utils/runtime-layout.js +7 -0
- package/cli/dist-bundle/{chunk-QQEV6D74.js → chunk-3XODDLRJ.js} +1 -1
- package/cli/dist-bundle/{chunk-VMB5673O.js → chunk-43XWL2PB.js} +30 -26
- package/cli/dist-bundle/{chunk-5EZ4EX6U.js → chunk-53L2JN7G.js} +1 -1
- package/cli/dist-bundle/{chunk-BWK6MPCB.js → chunk-5F7YP5IR.js} +1 -1
- package/cli/dist-bundle/{chunk-36SOQVAL.js → chunk-5QBYM33Q.js} +1 -1
- package/cli/dist-bundle/{chunk-HEMPQKD6.js → chunk-DU2BN46C.js} +1 -1
- package/cli/dist-bundle/{chunk-ICXF6PXA.js → chunk-ETKUVKJ2.js} +2 -2
- package/cli/dist-bundle/{chunk-PVBAGX5X.js → chunk-I7TGIK5N.js} +1 -1
- package/cli/dist-bundle/{chunk-B6Q5VKL7.js → chunk-IGN5UC3P.js} +1 -1
- package/cli/dist-bundle/chunk-MWOVYIBB.js +54 -0
- package/cli/dist-bundle/{chunk-D7N2GGJH.js → chunk-YHYRGWUH.js} +1 -1
- package/cli/dist-bundle/{chunk-VHFFSBVJ.js → chunk-YNCBBJ4V.js} +1 -1
- package/cli/dist-bundle/cli.js +153 -153
- package/cli/dist-bundle/{cold-preflight-ABU26DYW.js → cold-preflight-ZOPR7PWJ.js} +1 -1
- package/cli/dist-bundle/{demo-stage-EBIUCJBX.js → demo-stage-OHNTP2UJ.js} +1 -1
- package/cli/dist-bundle/{open-2KSAF6M2.js → open-XROJ6YEY.js} +1 -1
- package/cli/dist-bundle/project-7PTIOHGF.js +2 -0
- package/cli/dist-bundle/{services-V6Q55JR5.js → services-BIMF6MVU.js} +1 -1
- package/cli/dist-bundle/{tilt-port-owner-MWJ7P6NB.js → tilt-port-owner-ZY5M2JC4.js} +1 -1
- package/cli/package.json +1 -1
- package/package.json +12 -2
- package/runtime/platform/services/platform/proxy/service.yaml +14 -0
- package/cli/dist/commands/__tests__/project-e2e-helpers.js +0 -49
- package/cli/dist/commands/__tests__/ui-loading-screen.test.js +0 -16
- package/cli/dist/generator/__tests__/golden-helpers.js +0 -43
- package/cli/dist-bundle/chunk-763VK575.js +0 -54
- package/cli/dist-bundle/project-YD3C4ZV3.js +0 -2
- package/runtime/discovery/test_resource_snapshot.py +0 -253
- package/runtime/engine/assets/docker/wake-gateway/decide.test.ts +0 -177
- package/runtime/engine/topologies/tilt/manifest/tests/test_integration.star +0 -278
- package/runtime/engine/topologies/tilt/manifest/tests/test_loader_parser.star +0 -475
- package/runtime/engine/topologies/tilt/manifest/tests/test_manifest.star +0 -319
- package/runtime/engine/topologies/tilt/manifest/tests/test_validator.star +0 -472
- package/runtime/ext/ide-components/shared/test_config_service.py +0 -328
- /package/{shared-platform-engineering → runtime/shared-platform-engineering}/docker-templates/bun-hoisted-symlink-fix.sh +0 -0
- /package/{shared-platform-engineering → runtime/shared-platform-engineering}/docker-templates/infisical-entrypoint.sh +0 -0
- /package/{shared-platform-engineering → runtime/shared-platform-engineering}/docker-templates/install-deps.sh +0 -0
- /package/{shared-platform-engineering → runtime/shared-platform-engineering}/docker-templates/prisma-bun-client-link-fix.sh +0 -0
- /package/{shared-platform-engineering → runtime/shared-platform-engineering}/docker-templates/prisma-normalize-client.sh +0 -0
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2026 Flisk Landscape contributors
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
import { describe, expect, test } from "bun:test";
|
|
4
|
-
import {
|
|
5
|
-
COMPOSE_START_TIMEOUT_MS,
|
|
6
|
-
EARLY_RESPONSE_MS,
|
|
7
|
-
MAX_EARLY_RESPONSE_MS,
|
|
8
|
-
RETRY_AFTER_SECONDS,
|
|
9
|
-
TILT_TRIGGER_TIMEOUT_MS,
|
|
10
|
-
decideWakeAction,
|
|
11
|
-
earlyResponseMs,
|
|
12
|
-
evaluateReadiness,
|
|
13
|
-
isGatewayLivenessProbe,
|
|
14
|
-
wakeTimeoutMs,
|
|
15
|
-
} from "./decide";
|
|
16
|
-
|
|
17
|
-
describe("decideWakeAction", () => {
|
|
18
|
-
test("never-created resource: tilt trigger only, no Sablier start", () => {
|
|
19
|
-
const action = decideWakeAction({
|
|
20
|
-
resourceContainerName: "data-governance-api",
|
|
21
|
-
resourceState: "absent",
|
|
22
|
-
dependencies: [],
|
|
23
|
-
});
|
|
24
|
-
expect(action.tiltTriggerNames).toEqual(["data-governance-api"]);
|
|
25
|
-
expect(action.useSablierStart).toBe(false);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test("previously-run, now-exited resource: both tilt trigger and Sablier start", () => {
|
|
29
|
-
const action = decideWakeAction({
|
|
30
|
-
resourceContainerName: "data-governance-api",
|
|
31
|
-
resourceState: "exited",
|
|
32
|
-
dependencies: [],
|
|
33
|
-
});
|
|
34
|
-
expect(action.tiltTriggerNames).toEqual(["data-governance-api"]);
|
|
35
|
-
expect(action.useSablierStart).toBe(true);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test("created-but-not-started resource: both paths apply", () => {
|
|
39
|
-
const action = decideWakeAction({
|
|
40
|
-
resourceContainerName: "data-governance-api",
|
|
41
|
-
resourceState: "created",
|
|
42
|
-
dependencies: [],
|
|
43
|
-
});
|
|
44
|
-
expect(action.useSablierStart).toBe(true);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test("already running: no trigger needed", () => {
|
|
48
|
-
const action = decideWakeAction({
|
|
49
|
-
resourceContainerName: "data-governance-api",
|
|
50
|
-
resourceState: "running",
|
|
51
|
-
dependencies: [],
|
|
52
|
-
});
|
|
53
|
-
expect(action.tiltTriggerNames).toEqual([]);
|
|
54
|
-
expect(action.useSablierStart).toBe(false);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test("cold dependency is triggered alongside the resource (task 1.5 finding)", () => {
|
|
58
|
-
const action = decideWakeAction({
|
|
59
|
-
resourceContainerName: "data-governance-api",
|
|
60
|
-
resourceState: "absent",
|
|
61
|
-
dependencies: [
|
|
62
|
-
{ name: "postgres", state: "running" },
|
|
63
|
-
{ name: "data-governance-api-db-migrator", state: "absent" },
|
|
64
|
-
],
|
|
65
|
-
});
|
|
66
|
-
expect(action.tiltTriggerNames).toEqual([
|
|
67
|
-
"data-governance-api",
|
|
68
|
-
"data-governance-api-db-migrator",
|
|
69
|
-
]);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test("never-created resource with compose details: started directly, not queued in Tilt", () => {
|
|
73
|
-
const action = decideWakeAction({
|
|
74
|
-
resourceContainerName: "data-governance-api",
|
|
75
|
-
resourceState: "absent",
|
|
76
|
-
dependencies: [{ name: "peer-api", state: "absent" }],
|
|
77
|
-
hasComposeInvocation: true,
|
|
78
|
-
});
|
|
79
|
-
expect(action.useComposeStart).toBe(true);
|
|
80
|
-
// Dependencies carry no compose details, so they still go through Tilt.
|
|
81
|
-
expect(action.tiltTriggerNames).toEqual(["peer-api"]);
|
|
82
|
-
expect(action.useSablierStart).toBe(false);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test("existing (exited) container keeps the Sablier path even with compose details", () => {
|
|
86
|
-
const action = decideWakeAction({
|
|
87
|
-
resourceContainerName: "data-governance-api",
|
|
88
|
-
resourceState: "exited",
|
|
89
|
-
dependencies: [],
|
|
90
|
-
hasComposeInvocation: true,
|
|
91
|
-
});
|
|
92
|
-
expect(action.useComposeStart).toBe(false);
|
|
93
|
-
expect(action.tiltTriggerNames).toEqual(["data-governance-api"]);
|
|
94
|
-
expect(action.useSablierStart).toBe(true);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test("running dependency is not re-triggered", () => {
|
|
98
|
-
const action = decideWakeAction({
|
|
99
|
-
resourceContainerName: "data-governance-api",
|
|
100
|
-
resourceState: "running",
|
|
101
|
-
dependencies: [{ name: "postgres", state: "running" }],
|
|
102
|
-
});
|
|
103
|
-
expect(action.tiltTriggerNames).toEqual([]);
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
describe("wakeTimeoutMs", () => {
|
|
108
|
-
test("a direct compose start only waits for boot + healthcheck", () => {
|
|
109
|
-
expect(wakeTimeoutMs(true)).toBe(COMPOSE_START_TIMEOUT_MS);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
test("the tilt trigger path allows for an image build, under Bun's 255s idle cap", () => {
|
|
113
|
-
expect(wakeTimeoutMs(false)).toBe(TILT_TRIGGER_TIMEOUT_MS);
|
|
114
|
-
expect(TILT_TRIGGER_TIMEOUT_MS).toBeLessThan(255_000);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
test("an explicit X-Wake-Timeout-Ms wins", () => {
|
|
118
|
-
expect(wakeTimeoutMs(false, 5_000)).toBe(5_000);
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe("earlyResponseMs", () => {
|
|
123
|
-
test("holds a waking request for EARLY_RESPONSE_MS by default", () => {
|
|
124
|
-
expect(earlyResponseMs()).toBe(EARLY_RESPONSE_MS);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test("the default answers well before Bun's 255s idle cap drops the connection", () => {
|
|
128
|
-
expect(EARLY_RESPONSE_MS).toBeLessThan(255_000);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
test("an explicit X-Wake-Respond-Within-Ms wins, but is capped under Bun's idle limit", () => {
|
|
132
|
-
expect(earlyResponseMs(5_000)).toBe(5_000);
|
|
133
|
-
expect(earlyResponseMs(600_000)).toBe(MAX_EARLY_RESPONSE_MS);
|
|
134
|
-
expect(MAX_EARLY_RESPONSE_MS).toBeLessThan(255_000);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
test("tells the caller to retry soon", () => {
|
|
138
|
-
expect(RETRY_AFTER_SECONDS).toBeGreaterThan(0);
|
|
139
|
-
expect(RETRY_AFTER_SECONDS * 1000).toBeLessThan(EARLY_RESPONSE_MS);
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
describe("evaluateReadiness", () => {
|
|
144
|
-
test("ready once every required name reports healthy", () => {
|
|
145
|
-
const outcome = evaluateReadiness(["a", "b"], { a: true, b: true });
|
|
146
|
-
expect(outcome.ready).toBe(true);
|
|
147
|
-
expect(outcome.pending).toEqual([]);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
test("not ready while some names are still unhealthy", () => {
|
|
151
|
-
const outcome = evaluateReadiness(["a", "b"], { a: true, b: false });
|
|
152
|
-
expect(outcome.ready).toBe(false);
|
|
153
|
-
expect(outcome.pending).toEqual(["b"]);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
test("missing entries count as not healthy", () => {
|
|
157
|
-
const outcome = evaluateReadiness(["a", "b"], { a: true });
|
|
158
|
-
expect(outcome.ready).toBe(false);
|
|
159
|
-
expect(outcome.pending).toEqual(["b"]);
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
describe("isGatewayLivenessProbe", () => {
|
|
164
|
-
test("a bare GET /health from the image HEALTHCHECK is answered by the gateway", () => {
|
|
165
|
-
expect(isGatewayLivenessProbe("GET", "/health", new Headers())).toBe(true);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
test("a backend /health routed through the wake gateway is proxied, not answered", () => {
|
|
169
|
-
const routed = new Headers({ "X-Wake-Resource": "cold-api", "X-Wake-Container": "cold-api-1" });
|
|
170
|
-
expect(isGatewayLivenessProbe("GET", "/health", routed)).toBe(false);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
test("other methods and paths are not liveness probes", () => {
|
|
174
|
-
expect(isGatewayLivenessProbe("POST", "/health", new Headers())).toBe(false);
|
|
175
|
-
expect(isGatewayLivenessProbe("GET", "/health/ready", new Headers())).toBe(false);
|
|
176
|
-
});
|
|
177
|
-
});
|
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2026 Flisk Landscape contributors
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# =============================================================================
|
|
4
|
-
# 📋 MANIFEST MODULE - INTEGRATION TESTS (Phase 4)
|
|
5
|
-
# =============================================================================
|
|
6
|
-
# Path: .tilt/topologies/tilt/manifest/tests/test_integration.star
|
|
7
|
-
# Purpose: Integration tests for discovery system integration
|
|
8
|
-
# Status: Phase 4 of manifest system refactoring
|
|
9
|
-
# =============================================================================
|
|
10
|
-
|
|
11
|
-
load("../__init__.star", "Manifest")
|
|
12
|
-
load("../integration.star", "ManifestIntegration")
|
|
13
|
-
|
|
14
|
-
# =============================================================================
|
|
15
|
-
# TEST FRAMEWORK
|
|
16
|
-
# =============================================================================
|
|
17
|
-
|
|
18
|
-
test_results = {
|
|
19
|
-
'passed': 0,
|
|
20
|
-
'failed': 0,
|
|
21
|
-
'errors': [],
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
def assert_true(condition, message="Assertion failed"):
|
|
25
|
-
"""Assert that condition is true."""
|
|
26
|
-
if not condition:
|
|
27
|
-
test_results['failed'] += 1
|
|
28
|
-
test_results['errors'].append("FAIL: " + message)
|
|
29
|
-
else:
|
|
30
|
-
test_results['passed'] += 1
|
|
31
|
-
|
|
32
|
-
def assert_equal(expected, actual, message="Values not equal"):
|
|
33
|
-
"""Assert that expected equals actual."""
|
|
34
|
-
if expected != actual:
|
|
35
|
-
test_results['failed'] += 1
|
|
36
|
-
test_results['errors'].append(
|
|
37
|
-
"FAIL: {} - expected '{}', got '{}'".format(message, expected, actual)
|
|
38
|
-
)
|
|
39
|
-
else:
|
|
40
|
-
test_results['passed'] += 1
|
|
41
|
-
|
|
42
|
-
def assert_not_none(value, message="Value is None"):
|
|
43
|
-
"""Assert that value is not None."""
|
|
44
|
-
if value == None:
|
|
45
|
-
test_results['failed'] += 1
|
|
46
|
-
test_results['errors'].append("FAIL: " + message)
|
|
47
|
-
else:
|
|
48
|
-
test_results['passed'] += 1
|
|
49
|
-
|
|
50
|
-
# =============================================================================
|
|
51
|
-
# TEST SUITE: Integration Functions
|
|
52
|
-
# =============================================================================
|
|
53
|
-
|
|
54
|
-
def _test_integration_functions():
|
|
55
|
-
"""Test integration functions are accessible."""
|
|
56
|
-
print("🔍 Testing integration functions...")
|
|
57
|
-
|
|
58
|
-
# Test via facade
|
|
59
|
-
assert_not_none(Manifest.load_and_validate_integration, "load_and_validate_integration should be accessible")
|
|
60
|
-
assert_not_none(Manifest.load_all_integration, "load_all_integration should be accessible")
|
|
61
|
-
assert_not_none(Manifest.convert_to_resource, "convert_to_resource should be accessible")
|
|
62
|
-
assert_not_none(Manifest.get_validation_summary, "get_validation_summary should be accessible")
|
|
63
|
-
assert_not_none(Manifest.check_port_conflicts, "check_port_conflicts should be accessible")
|
|
64
|
-
assert_not_none(Manifest.check_dependencies_valid, "check_dependencies_valid should be accessible")
|
|
65
|
-
|
|
66
|
-
# Test via integration module
|
|
67
|
-
assert_not_none(ManifestIntegration.load_and_validate, "ManifestIntegration.load_and_validate should exist")
|
|
68
|
-
assert_not_none(ManifestIntegration.load_all, "ManifestIntegration.load_all should exist")
|
|
69
|
-
|
|
70
|
-
print("✅ Integration functions accessible\n")
|
|
71
|
-
|
|
72
|
-
# =============================================================================
|
|
73
|
-
# TEST SUITE: Convert to Resource
|
|
74
|
-
# =============================================================================
|
|
75
|
-
|
|
76
|
-
def _test_convert_to_resource():
|
|
77
|
-
"""Test manifest to resource conversion."""
|
|
78
|
-
print("🔍 Testing convert_to_resource...")
|
|
79
|
-
|
|
80
|
-
# Test backend conversion
|
|
81
|
-
backend_manifest = {
|
|
82
|
-
'appName': 'user-management-backend',
|
|
83
|
-
'appType': 'backend',
|
|
84
|
-
'stack': 'user',
|
|
85
|
-
'port': 4000,
|
|
86
|
-
'syncs': ['src', 'prisma'],
|
|
87
|
-
'_resource_path': 'services/product/user/user-management-backend',
|
|
88
|
-
'_manifest': {'runtime': 'bun'},
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
resource = Manifest.convert_to_resource(backend_manifest)
|
|
92
|
-
|
|
93
|
-
assert_equal('user-management-backend', resource['name'], "Should preserve name")
|
|
94
|
-
assert_equal(4000, resource['port'], "Should preserve port")
|
|
95
|
-
assert_equal('user', resource['stack'], "Should preserve stack")
|
|
96
|
-
assert_true('frontend' not in resource or not resource['frontend'], "Should not mark as frontend")
|
|
97
|
-
assert_equal('services/product/user/user-management-backend', resource['_resource_path'], "Should preserve service path")
|
|
98
|
-
|
|
99
|
-
# Test frontend conversion
|
|
100
|
-
frontend_manifest = {
|
|
101
|
-
'appName': 'user-management-frontend',
|
|
102
|
-
'appType': 'frontend',
|
|
103
|
-
'stack': 'user',
|
|
104
|
-
'port': 3000,
|
|
105
|
-
'backendName': 'user-management-backend',
|
|
106
|
-
'_resource_path': 'services/product/user/user-management-frontend',
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
resource = Manifest.convert_to_resource(frontend_manifest)
|
|
110
|
-
|
|
111
|
-
assert_equal('user-management-frontend', resource['name'], "Should preserve name")
|
|
112
|
-
assert_true(resource.get('frontend', False), "Should mark as frontend")
|
|
113
|
-
assert_equal('user-management-backend', resource['backendName'], "Should preserve backendName")
|
|
114
|
-
|
|
115
|
-
print("✅ Convert to resource tests complete\n")
|
|
116
|
-
|
|
117
|
-
# =============================================================================
|
|
118
|
-
# TEST SUITE: Validation Summary
|
|
119
|
-
# =============================================================================
|
|
120
|
-
|
|
121
|
-
def _test_validation_summary():
|
|
122
|
-
"""Test validation summary generation."""
|
|
123
|
-
print("🔍 Testing validation summary...")
|
|
124
|
-
|
|
125
|
-
manifests = [
|
|
126
|
-
{
|
|
127
|
-
'appName': 'valid-service',
|
|
128
|
-
'appType': 'backend',
|
|
129
|
-
'stack': 'user',
|
|
130
|
-
'port': 4000,
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
'appName': 'valid-frontend',
|
|
134
|
-
'appType': 'frontend',
|
|
135
|
-
'stack': 'user',
|
|
136
|
-
'port': 3000,
|
|
137
|
-
'backendName': 'valid-service',
|
|
138
|
-
},
|
|
139
|
-
]
|
|
140
|
-
|
|
141
|
-
summary = Manifest.get_validation_summary(manifests)
|
|
142
|
-
|
|
143
|
-
assert_equal(2, summary['total'], "Should count total manifests")
|
|
144
|
-
assert_true('valid' in summary, "Should have valid count")
|
|
145
|
-
assert_true('invalid' in summary, "Should have invalid count")
|
|
146
|
-
assert_true('by_severity' in summary, "Should have severity breakdown")
|
|
147
|
-
|
|
148
|
-
print("✅ Validation summary tests complete\n")
|
|
149
|
-
|
|
150
|
-
# =============================================================================
|
|
151
|
-
# TEST SUITE: Port Conflicts
|
|
152
|
-
# =============================================================================
|
|
153
|
-
|
|
154
|
-
def _test_port_conflicts():
|
|
155
|
-
"""Test port conflict detection."""
|
|
156
|
-
print("🔍 Testing port conflict detection...")
|
|
157
|
-
|
|
158
|
-
# No conflicts
|
|
159
|
-
no_conflict = [
|
|
160
|
-
{'appName': 'service-1', 'port': 4000},
|
|
161
|
-
{'appName': 'service-2', 'port': 4001},
|
|
162
|
-
{'appName': 'service-3', 'port': 4002},
|
|
163
|
-
]
|
|
164
|
-
|
|
165
|
-
conflicts = Manifest.check_port_conflicts(no_conflict)
|
|
166
|
-
assert_equal(0, len(conflicts), "Should find no conflicts for unique ports")
|
|
167
|
-
|
|
168
|
-
# With conflicts
|
|
169
|
-
with_conflict = [
|
|
170
|
-
{'appName': 'service-1', 'port': 4000},
|
|
171
|
-
{'appName': 'service-2', 'port': 4000}, # Conflict!
|
|
172
|
-
{'appName': 'service-3', 'port': 4001},
|
|
173
|
-
]
|
|
174
|
-
|
|
175
|
-
conflicts = Manifest.check_port_conflicts(with_conflict)
|
|
176
|
-
assert_true(len(conflicts) > 0, "Should find port conflicts")
|
|
177
|
-
|
|
178
|
-
print("✅ Port conflict tests complete\n")
|
|
179
|
-
|
|
180
|
-
# =============================================================================
|
|
181
|
-
# TEST SUITE: Dependency Validation
|
|
182
|
-
# =============================================================================
|
|
183
|
-
|
|
184
|
-
def _test_dependency_validation():
|
|
185
|
-
"""Test dependency validation across services."""
|
|
186
|
-
print("🔍 Testing dependency validation...")
|
|
187
|
-
|
|
188
|
-
manifests = [
|
|
189
|
-
{
|
|
190
|
-
'appName': 'identity-backend',
|
|
191
|
-
'appType': 'backend',
|
|
192
|
-
'stack': 'identity',
|
|
193
|
-
'port': 4004,
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
'appName': 'user-backend',
|
|
197
|
-
'appType': 'backend',
|
|
198
|
-
'stack': 'user',
|
|
199
|
-
'port': 4000,
|
|
200
|
-
'dependsOn': ['identity-backend'], # Valid
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
'appName': 'user-frontend',
|
|
204
|
-
'appType': 'frontend',
|
|
205
|
-
'stack': 'user',
|
|
206
|
-
'port': 3000,
|
|
207
|
-
'backendName': 'user-backend', # Valid
|
|
208
|
-
},
|
|
209
|
-
{
|
|
210
|
-
'appName': 'bad-service',
|
|
211
|
-
'appType': 'backend',
|
|
212
|
-
'stack': 'user',
|
|
213
|
-
'port': 4001,
|
|
214
|
-
'dependsOn': ['nonexistent-service'], # Invalid
|
|
215
|
-
},
|
|
216
|
-
]
|
|
217
|
-
|
|
218
|
-
errors = Manifest.check_dependencies_valid(manifests)
|
|
219
|
-
|
|
220
|
-
# Should find at least one error for nonexistent dependency
|
|
221
|
-
assert_true(len(errors) > 0, "Should find dependency issues")
|
|
222
|
-
|
|
223
|
-
print("✅ Dependency validation tests complete\n")
|
|
224
|
-
|
|
225
|
-
# =============================================================================
|
|
226
|
-
# TEST SUITE: Feature Flag
|
|
227
|
-
# =============================================================================
|
|
228
|
-
|
|
229
|
-
def _test_feature_flag():
|
|
230
|
-
"""Test the feature flag system."""
|
|
231
|
-
print("🔍 Testing feature flag...")
|
|
232
|
-
|
|
233
|
-
# Check if flag is accessible
|
|
234
|
-
use_new = ManifestIntegration.use_new_system()
|
|
235
|
-
assert_true(use_new != None, "Feature flag should return boolean")
|
|
236
|
-
|
|
237
|
-
print("✅ Feature flag tests complete\n")
|
|
238
|
-
|
|
239
|
-
# =============================================================================
|
|
240
|
-
# MAIN
|
|
241
|
-
# =============================================================================
|
|
242
|
-
|
|
243
|
-
def run_tests():
|
|
244
|
-
"""Run all Phase 4 integration tests."""
|
|
245
|
-
print("\n" + "="*70)
|
|
246
|
-
print("📋 MANIFEST MODULE - PHASE 4 INTEGRATION TESTS")
|
|
247
|
-
print("="*70 + "\n")
|
|
248
|
-
|
|
249
|
-
# Run all test suites
|
|
250
|
-
_test_integration_functions()
|
|
251
|
-
_test_convert_to_resource()
|
|
252
|
-
_test_validation_summary()
|
|
253
|
-
_test_port_conflicts()
|
|
254
|
-
_test_dependency_validation()
|
|
255
|
-
_test_feature_flag()
|
|
256
|
-
|
|
257
|
-
# Print results
|
|
258
|
-
print("\n" + "="*70)
|
|
259
|
-
print("📊 TEST RESULTS")
|
|
260
|
-
print("="*70)
|
|
261
|
-
print("✅ Passed: {}".format(test_results['passed']))
|
|
262
|
-
print("❌ Failed: {}".format(test_results['failed']))
|
|
263
|
-
|
|
264
|
-
if test_results['errors']:
|
|
265
|
-
print("\n📝 ERRORS:")
|
|
266
|
-
for error in test_results['errors']:
|
|
267
|
-
print(" " + error)
|
|
268
|
-
else:
|
|
269
|
-
print("\n🎉 All Phase 4 integration tests passed!")
|
|
270
|
-
|
|
271
|
-
print("="*70 + "\n")
|
|
272
|
-
|
|
273
|
-
return test_results['failed'] == 0
|
|
274
|
-
|
|
275
|
-
# Export test runner
|
|
276
|
-
TestIntegration = struct(
|
|
277
|
-
run=run_tests,
|
|
278
|
-
)
|