Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Local AWS cloud emulator. Part of the faisca project family.
## Product Context

- FakeCloud is a local AWS emulator focused on high-fidelity behavior and AWS-compatible responses.
- Current project state: 106 AWS services, 7,612 operations, 257,288/257,288 Smithy conformance variants pass — true 100% across every implemented service, no flake margin. See [the parity matrix](website/content/docs/parity.md) for the full service-by-service breakdown of control-plane vs data-plane coverage and known limitations.
- Current project state: 107 AWS services, 7,657 operations, 258,545/258,545 Smithy conformance variants pass — true 100% across every implemented service, no flake margin. See [the parity matrix](website/content/docs/parity.md) for the full service-by-service breakdown of control-plane vs data-plane coverage and known limitations.
- The broader roadmap prioritizes services that LocalStack keeps behind paid tiers, especially ECS, ELB/ALB, CloudFront, CloudWatch Metrics, and EC2.
- Introspection SDKs (Rust, Python, TypeScript, Go, PHP, Java, .NET) are already built and maintained for the `/_fakecloud/*` endpoints.

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Works as a drop-in for LocalStack in CI, with Terraform (`endpoints` block), CDK
## Why fakecloud

- **Free, forever.** AGPL-3.0, no paid tier, no account, no token.
- **True 100% conformance.** 257,288 Smithy-model-generated test variants pass on every commit, validated against AWS's own Smithy models. CI also runs upstream `terraform-provider-aws` `TestAcc*` suites to catch waiter/field/drift bugs that SDK tests miss.
- **True 100% conformance.** 258,545 Smithy-model-generated test variants pass on every commit, validated against AWS's own Smithy models. CI also runs upstream `terraform-provider-aws` `TestAcc*` suites to catch waiter/field/drift bugs that SDK tests miss.
- **Real cross-service wiring.** EventBridge -> Step Functions, S3 -> Lambda, SES inbound -> S3/SNS/Lambda, and 15+ more integrations execute end-to-end.
- **Real infrastructure for stateful services.** Lambda (31 runtimes), RDS (Postgres/MySQL/MariaDB/Oracle/SQL Server/Db2), ElastiCache (Redis/Valkey/Memcached), ECS, and EC2 run as real containers. Use Docker (default) or native Kubernetes Pods via `FAKECLOUD_CONTAINER_BACKEND=k8s`. See the [Kubernetes backend guide](https://fakecloud.dev/docs/guides/kubernetes-backend/).
- **Single binary.** ~19 MB, ~10 MiB idle, ~300ms startup. No Docker needed to run fakecloud itself.
Expand All @@ -60,7 +60,7 @@ Works as a drop-in for LocalStack in CI, with Terraform (`endpoints` block), CDK

## Supported services

106 services, 7,612 operations, and true 100% conformance across every implemented service.
107 services, 7,657 operations, and true 100% conformance across every implemented service.

Highlights: S3, DynamoDB, SQS, SNS, EventBridge, Lambda, IAM, STS, KMS, Secrets Manager, CloudFormation, SES, Cognito, Kinesis, RDS (6 real engines), ElastiCache, ECS/ECR, EC2, Step Functions, API Gateway v1/v2, Bedrock, and 80+ more.

Expand All @@ -78,7 +78,7 @@ Since March 2026, LocalStack's Community image requires an account and token, an
| License | AGPL-3.0, free for commercial use | Proprietary, paid plans |
| Auth | None | Account + token required |
| Footprint | ~19 MB binary, ~10 MiB idle, ~300ms start, no Docker | ~1 GB image, ~150 MiB idle, ~3s start, Docker required |
| Conformance | true 100% (257,288 Smithy variants) | partial |
| Conformance | true 100% (258,545 Smithy variants) | partial |
| Paywalled services | None (RDS, Cognito, SES, ElastiCache, ECS/ECR, EKS, Redshift, and more are all free) | Many core services paid-only |
| Test-assertion SDKs | TypeScript, Python, Go, PHP, Java, Rust, .NET | Python, Java |

Expand Down
4 changes: 4 additions & 0 deletions aws-models/service-map.json
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@
"repo_dir": "backup",
"service_name": "backup"
},
"batch": {
"repo_dir": "batch",
"service_name": "batch"
},
"ram": {
"repo_dir": "ram",
"service_name": "ram"
Expand Down
2 changes: 1 addition & 1 deletion conformance-baseline-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

`conformance-baseline.json` is the floor a PR must clear in CI. Every
service is pinned at its full observed pass count — currently
257,288 / 257,288 variants across all 106 services. CI fails any PR with a
258,545 / 258,545 variants across all 107 services. CI fails any PR with a
failing variant, and any PR that drops a service below its baseline pass
count (no flake margin).

Expand Down
8 changes: 6 additions & 2 deletions conformance-baseline.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"variants_passed": 257288,
"total_variants": 257288,
"variants_passed": 258545,
"total_variants": 258545,
"per_service": {
"ce": {
"passed": 1781,
Expand Down Expand Up @@ -429,6 +429,10 @@
"firehose": {
"passed": 416,
"total": 416
},
"batch": {
"passed": 1257,
"total": 1257
}
}
}
1 change: 1 addition & 0 deletions crates/fakecloud-batch/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ parking_lot = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
uuid = { workspace = true }

[dev-dependencies]
Expand Down
28 changes: 25 additions & 3 deletions crates/fakecloud-batch/src/extended.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn now_ms() -> i64 {
chrono::Utc::now().timestamp_millis()
}

fn required_str<'a>(body: &'a Value, key: &str) -> Result<&'a str, AwsServiceError> {
pub(crate) fn required_str<'a>(body: &'a Value, key: &str) -> Result<&'a str, AwsServiceError> {
body.get(key)
.and_then(Value::as_str)
.filter(|s| !s.is_empty())
Expand Down Expand Up @@ -238,6 +238,8 @@ pub(crate) enum Admission {
Admitted,
/// At least one requirement does not fit right now: wait at RUNNABLE.
Wait,
/// The job was cancelled or terminated (or finished): never start it.
Stopped,
}

/// Atomically admit a job against its consumable resources. On success with
Expand All @@ -248,6 +250,9 @@ pub(crate) fn admit_job(st: &mut BatchState, job_id: &str) -> Admission {
let Some(job) = st.jobs.get(job_id) else {
return Admission::Admitted;
};
if crate::service::is_terminal(job) {
return Admission::Stopped;
}
let reqs = job_consumable_requirements(job);
if reqs.is_empty() {
return Admission::Admitted;
Expand Down Expand Up @@ -2100,6 +2105,23 @@ mod tests {
}
}

/// A deleted resource's tags are purged, and listing them is a
/// ClientException since the resource no longer exists.
async fn assert_deleted_tags_gone(s: &BatchService, arn: &str) {
assert!(!s
.state
.read()
.get("123456789012")
.unwrap()
.tags
.contains_key(arn));
let path = format!("/v1/tags/{}", arn.replace('/', "%2F"));
match s.handle(req_with(Method::GET, &path, "", json!({}))).await {
Err(e) => assert_eq!(e.code(), "ClientException"),
Ok(_) => panic!("ListTagsForResource on deleted {arn} must be rejected"),
}
}

async fn list_tags(s: &BatchService, arn: &str) -> Value {
// The SDK percent-encodes the ARN label (its `/` becomes %2F).
let path = format!("/v1/tags/{}", arn.replace('/', "%2F"));
Expand Down Expand Up @@ -2226,7 +2248,7 @@ mod tests {
json!({"consumableResource": "licenses"}),
)
.await;
assert_eq!(list_tags(&s, &arn).await, json!({}));
assert_deleted_tags_gone(&s, &arn).await;
}

#[tokio::test]
Expand Down Expand Up @@ -2677,7 +2699,7 @@ mod tests {
assert_eq!(d["capacityLimits"][0]["maxCapacity"], 8);
ok(&s, "deletequotashare", json!({"quotaShareArn": arn})).await;
client_err(&s, "describequotashare", json!({"quotaShareArn": arn})).await;
assert_eq!(list_tags(&s, &arn).await, json!({}));
assert_deleted_tags_gone(&s, &arn).await;
}

const PAYLOAD: &str = r#"{"TrainingJobName":"t","ResourceConfig":{"InstanceType":"ml.m5.large","InstanceCount":2,"VolumeSizeInGB":10}}"#;
Expand Down
2 changes: 1 addition & 1 deletion crates/fakecloud-batch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod extended;
pub mod service;
pub mod state;

pub use service::{batch_arn, BatchService};
pub use service::{batch_arn, normalize_compute_environment_order, BatchService};
pub use state::{
BatchAccounts, BatchSnapshot, BatchState, SharedBatchState, BATCH_SNAPSHOT_SCHEMA_VERSION,
};
Loading
Loading