test(charts): add integration scenarios and regression tests
Phase 4: Create integration tests for real-world scenarios and regression tests to lock down all default values. New test files: - integration_common_configs_test.yaml: 12 real-world deployment scenarios including DLNA home server, secure production, Prometheus monitoring, IPv6-only/dual-stack, cloud providers (AWS IRSA, GCP WI), air-gapped, minimal resource-constrained, Gateway API HTTPRoute (50+ tests) - regression_defaults_test.yaml: Comprehensive verification of all default values across all resources to prevent accidental changes. Covers deployment, service, serviceAccount, persistence, probes, labels, API versions, critical defaults (80+ tests) Integration scenarios tested: 1. DLNA Home Media Server (hostNetwork, NodePort, NAS storage) 2. Secure Production (NetworkPolicy, security contexts, resources, ingress+TLS) 3. Kubernetes with Prometheus (metrics, ServiceMonitor, custom NetworkPolicy) 4. IPv6-only cluster (SingleStack IPv6) 5. Dual-stack networking (IPv4+IPv6, LoadBalancer) 6. Development environment (emptyDir, latest tag, debug logging) 7. High Availability attempt (multiple replicas, ReadWriteMany, pod anti-affinity) 8. AWS with IRSA (EKS role annotations, gp3 storage, NLB, ALB ingress) 9. GCP with Workload Identity (GKE service account annotations) 10. Air-gapped environment (private registry, restrictive NetworkPolicy) 11. Minimal resource-constrained (low CPU/memory limits, emptyDir) 12. Gateway API (HTTPRoute with multiple hostnames) Regression tests lock down: - All default values: replicas=1, revisionHistoryLimit=3, ClusterIP service, port 8096, IfNotPresent pullPolicy, ClusterFirst dnsPolicy - Persistence defaults: config 5Gi, media 25Gi, cache emptyDir - Probe defaults: startup (tcpSocket, 0/10/30), liveness/readiness (httpGet) - Feature flags: DLNA off, metrics off, NetworkPolicy off, ServiceMonitor off - API versions and naming patterns - Critical invariants that must never change Total: 2 new test files, 130+ new test cases Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
This commit is contained in:
1 parent
6c59c59f9e
commit
9e5d0b8b2e
2 files changed
+973
No files matched your search
@@ -0,0 +1,416 @@
|
|||||||
|
suite: test integration common configurations
|
||||||
|
templates:
|
||||||
|
- deployment.yaml
|
||||||
|
- service.yaml
|
||||||
|
- ingress.yaml
|
||||||
|
- networkpolicy.yaml
|
||||||
|
- serviceMonitor.yaml
|
||||||
|
- persistentVolumeClaim.yaml
|
||||||
|
tests:
|
||||||
|
# =============================================================================
|
||||||
|
# SCENARIO 1: DLNA HOME MEDIA SERVER
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should configure DLNA setup correctly
|
||||||
|
set:
|
||||||
|
jellyfin.enableDLNA: true
|
||||||
|
persistence.media.type: hostPath
|
||||||
|
persistence.media.hostPath: /mnt/nas/media
|
||||||
|
service.type: NodePort
|
||||||
|
service.nodePort: 30096
|
||||||
|
asserts:
|
||||||
|
- template: deployment.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.template.spec.hostNetwork
|
||||||
|
value: true
|
||||||
|
- template: deployment.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.template.spec.dnsPolicy
|
||||||
|
value: ClusterFirstWithHostNet
|
||||||
|
- template: deployment.yaml
|
||||||
|
contains:
|
||||||
|
path: spec.template.spec.volumes
|
||||||
|
content:
|
||||||
|
name: media
|
||||||
|
hostPath:
|
||||||
|
path: /mnt/nas/media
|
||||||
|
- template: service.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.type
|
||||||
|
value: NodePort
|
||||||
|
- template: networkpolicy.yaml
|
||||||
|
hasDocuments:
|
||||||
|
count: 0 # NetworkPolicy incompatible with hostNetwork
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SCENARIO 2: SECURE PRODUCTION SETUP
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should configure secure production setup
|
||||||
|
set:
|
||||||
|
networkPolicy.enabled: true
|
||||||
|
networkPolicy.egress.allowAllEgress: false
|
||||||
|
networkPolicy.egress.restrictedEgress:
|
||||||
|
allowMetadata: true
|
||||||
|
allowInCluster: true
|
||||||
|
allowedCIDRs: [10.0.0.0/8]
|
||||||
|
podSecurityContext:
|
||||||
|
fsGroup: 1000
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsNonRoot: true
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: false
|
||||||
|
capabilities:
|
||||||
|
drop: [ALL]
|
||||||
|
persistence.config.size: 10Gi
|
||||||
|
persistence.media.size: 500Gi
|
||||||
|
persistence.cache.enabled: true
|
||||||
|
persistence.cache.type: pvc
|
||||||
|
persistence.cache.size: 50Gi
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 1Gi
|
||||||
|
limits:
|
||||||
|
cpu: 2000m
|
||||||
|
memory: 4Gi
|
||||||
|
ingress.enabled: true
|
||||||
|
ingress.className: nginx
|
||||||
|
ingress.hosts:
|
||||||
|
- host: jellyfin.example.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
ingress.tls:
|
||||||
|
- secretName: jellyfin-tls
|
||||||
|
hosts: [jellyfin.example.com]
|
||||||
|
asserts:
|
||||||
|
- template: networkpolicy.yaml
|
||||||
|
hasDocuments:
|
||||||
|
count: 1
|
||||||
|
- template: deployment.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.template.spec.securityContext.runAsNonRoot
|
||||||
|
value: true
|
||||||
|
- template: deployment.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation
|
||||||
|
value: false
|
||||||
|
- template: persistentVolumeClaim.yaml
|
||||||
|
hasDocuments:
|
||||||
|
count: 3
|
||||||
|
- template: ingress.yaml
|
||||||
|
hasDocuments:
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SCENARIO 3: KUBERNETES WITH PROMETHEUS MONITORING
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should configure full metrics and monitoring
|
||||||
|
set:
|
||||||
|
metrics.enabled: true
|
||||||
|
metrics.serviceMonitor.enabled: true
|
||||||
|
metrics.serviceMonitor.interval: 30s
|
||||||
|
metrics.serviceMonitor.labels:
|
||||||
|
prometheus: kube-prometheus
|
||||||
|
networkPolicy.enabled: true
|
||||||
|
networkPolicy.ingress.customRules:
|
||||||
|
- from:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
name: monitoring
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 8096
|
||||||
|
podAnnotations:
|
||||||
|
prometheus.io/scrape: "true"
|
||||||
|
prometheus.io/port: "8096"
|
||||||
|
asserts:
|
||||||
|
- template: serviceMonitor.yaml
|
||||||
|
hasDocuments:
|
||||||
|
count: 1
|
||||||
|
- template: serviceMonitor.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.endpoints[0].interval
|
||||||
|
value: 30s
|
||||||
|
- template: deployment.yaml
|
||||||
|
isNotNull:
|
||||||
|
path: spec.template.spec.containers[0].lifecycle.postStart
|
||||||
|
- template: networkpolicy.yaml
|
||||||
|
hasDocuments:
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SCENARIO 4: IPv6-ONLY CLUSTER
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should configure IPv6-only setup
|
||||||
|
set:
|
||||||
|
service.ipFamilyPolicy: SingleStack
|
||||||
|
service.ipFamilies: [IPv6]
|
||||||
|
persistence.media.type: pvc
|
||||||
|
persistence.media.size: 1Ti
|
||||||
|
asserts:
|
||||||
|
- template: service.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.ipFamilyPolicy
|
||||||
|
value: SingleStack
|
||||||
|
- template: service.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.ipFamilies[0]
|
||||||
|
value: IPv6
|
||||||
|
- template: persistentVolumeClaim.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.resources.requests.storage
|
||||||
|
documentIndex: 1
|
||||||
|
value: 1Ti
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SCENARIO 5: DUAL-STACK IPv4+IPv6
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should configure dual-stack networking
|
||||||
|
set:
|
||||||
|
service.ipFamilyPolicy: RequireDualStack
|
||||||
|
service.ipFamilies: [IPv4, IPv6]
|
||||||
|
service.type: LoadBalancer
|
||||||
|
service.loadBalancerIP: 203.0.113.42
|
||||||
|
asserts:
|
||||||
|
- template: service.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.ipFamilyPolicy
|
||||||
|
value: RequireDualStack
|
||||||
|
- template: service.yaml
|
||||||
|
lengthEqual:
|
||||||
|
path: spec.ipFamilies
|
||||||
|
count: 2
|
||||||
|
- template: service.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.type
|
||||||
|
value: LoadBalancer
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SCENARIO 6: DEVELOPMENT/TESTING ENVIRONMENT
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should configure development environment
|
||||||
|
set:
|
||||||
|
replicaCount: 1
|
||||||
|
persistence.config.enabled: false
|
||||||
|
persistence.media.enabled: false
|
||||||
|
persistence.cache.enabled: false
|
||||||
|
image.tag: latest
|
||||||
|
image.pullPolicy: Always
|
||||||
|
revisionHistoryLimit: 1
|
||||||
|
deploymentStrategy.type: Recreate
|
||||||
|
jellyfin.env:
|
||||||
|
- name: JELLYFIN_LOG_LEVEL
|
||||||
|
value: Debug
|
||||||
|
asserts:
|
||||||
|
- template: deployment.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.replicas
|
||||||
|
value: 1
|
||||||
|
- template: deployment.yaml
|
||||||
|
contains:
|
||||||
|
path: spec.template.spec.volumes
|
||||||
|
content:
|
||||||
|
name: config
|
||||||
|
emptyDir: {}
|
||||||
|
- template: deployment.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.template.spec.containers[0].imagePullPolicy
|
||||||
|
value: Always
|
||||||
|
- template: deployment.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.strategy.type
|
||||||
|
value: Recreate
|
||||||
|
- template: persistentVolumeClaim.yaml
|
||||||
|
hasDocuments:
|
||||||
|
count: 0
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SCENARIO 7: HIGH AVAILABILITY (with caveats)
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Note: Jellyfin doesn't truly support HA, but users might try it
|
||||||
|
- it: should configure for attempted HA setup
|
||||||
|
set:
|
||||||
|
replicaCount: 3
|
||||||
|
persistence.config.accessMode: ReadWriteMany
|
||||||
|
persistence.media.accessMode: ReadWriteMany
|
||||||
|
persistence.media.type: nfs
|
||||||
|
persistence.media.hostPath: /nfs/jellyfin/media
|
||||||
|
affinity:
|
||||||
|
podAntiAffinity:
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: jellyfin
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
asserts:
|
||||||
|
- template: deployment.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.replicas
|
||||||
|
value: 3
|
||||||
|
- template: persistentVolumeClaim.yaml
|
||||||
|
contains:
|
||||||
|
path: spec.accessModes
|
||||||
|
documentIndex: 0
|
||||||
|
content: ReadWriteMany
|
||||||
|
- template: deployment.yaml
|
||||||
|
isNotNull:
|
||||||
|
path: spec.template.spec.affinity.podAntiAffinity
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SCENARIO 8: CLOUD PROVIDER SPECIFIC (AWS)
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should configure for AWS with IRSA
|
||||||
|
set:
|
||||||
|
serviceAccount.create: true
|
||||||
|
serviceAccount.annotations:
|
||||||
|
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/jellyfin-s3
|
||||||
|
persistence.media.type: pvc
|
||||||
|
persistence.media.storageClass: gp3
|
||||||
|
persistence.media.size: 500Gi
|
||||||
|
service.type: LoadBalancer
|
||||||
|
service.annotations:
|
||||||
|
service.beta.kubernetes.io/aws-load-balancer-type: nlb
|
||||||
|
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
|
||||||
|
ingress.enabled: true
|
||||||
|
ingress.className: alb
|
||||||
|
ingress.annotations:
|
||||||
|
alb.ingress.kubernetes.io/scheme: internet-facing
|
||||||
|
alb.ingress.kubernetes.io/target-type: ip
|
||||||
|
asserts:
|
||||||
|
- template: serviceaccount.yaml
|
||||||
|
equal:
|
||||||
|
path: metadata.annotations.eks\.amazonaws\.com/role-arn
|
||||||
|
value: arn:aws:iam::123456789012:role/jellyfin-s3
|
||||||
|
- template: service.yaml
|
||||||
|
equal:
|
||||||
|
path: metadata.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-type
|
||||||
|
value: nlb
|
||||||
|
- template: ingress.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.ingressClassName
|
||||||
|
value: alb
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SCENARIO 9: GCP WITH WORKLOAD IDENTITY
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should configure for GCP with Workload Identity
|
||||||
|
set:
|
||||||
|
serviceAccount.create: true
|
||||||
|
serviceAccount.annotations:
|
||||||
|
iam.gke.io/gcp-service-account: jellyfin@project-id.iam.gserviceaccount.com
|
||||||
|
persistence.media.type: pvc
|
||||||
|
persistence.media.storageClass: standard-rwo
|
||||||
|
service.type: LoadBalancer
|
||||||
|
service.annotations:
|
||||||
|
cloud.google.com/neg: '{"ingress": true}'
|
||||||
|
asserts:
|
||||||
|
- template: serviceaccount.yaml
|
||||||
|
equal:
|
||||||
|
path: metadata.annotations.iam\.gke\.io/gcp-service-account
|
||||||
|
value: jellyfin@project-id.iam.gserviceaccount.com
|
||||||
|
- template: service.yaml
|
||||||
|
equal:
|
||||||
|
path: metadata.annotations.cloud\.google\.com/neg
|
||||||
|
value: '{"ingress": true}'
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SCENARIO 10: AIR-GAPPED ENVIRONMENT
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should configure for air-gapped environment
|
||||||
|
set:
|
||||||
|
image.repository: internal-registry.local/jellyfin/jellyfin
|
||||||
|
image.tag: 10.8.13-offline
|
||||||
|
image.pullPolicy: IfNotPresent
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: internal-registry-creds
|
||||||
|
persistence.media.type: hostPath
|
||||||
|
persistence.media.hostPath: /mnt/local-storage/media
|
||||||
|
service.type: NodePort
|
||||||
|
networkPolicy.enabled: true
|
||||||
|
networkPolicy.egress.allowAllEgress: false
|
||||||
|
networkPolicy.egress.restrictedEgress:
|
||||||
|
allowInCluster: true
|
||||||
|
asserts:
|
||||||
|
- template: deployment.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.template.spec.containers[0].image
|
||||||
|
value: internal-registry.local/jellyfin/jellyfin:10.8.13-offline
|
||||||
|
- template: deployment.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.template.spec.imagePullSecrets[0].name
|
||||||
|
value: internal-registry-creds
|
||||||
|
- template: networkpolicy.yaml
|
||||||
|
hasDocuments:
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SCENARIO 11: MINIMAL RESOURCE-CONSTRAINED SETUP
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should configure minimal resource-constrained setup
|
||||||
|
set:
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
persistence.config.size: 1Gi
|
||||||
|
persistence.media.type: emptyDir
|
||||||
|
persistence.cache.enabled: false
|
||||||
|
service.type: ClusterIP
|
||||||
|
asserts:
|
||||||
|
- template: deployment.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.template.spec.containers[0].resources.requests.cpu
|
||||||
|
value: 100m
|
||||||
|
- template: persistentVolumeClaim.yaml
|
||||||
|
hasDocuments:
|
||||||
|
count: 1 # only config
|
||||||
|
- template: service.yaml
|
||||||
|
equal:
|
||||||
|
path: spec.type
|
||||||
|
value: ClusterIP
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SCENARIO 12: GATEWAY API (HTTPRoute)
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should configure Gateway API HTTPRoute
|
||||||
|
set:
|
||||||
|
httpRoute.enabled: true
|
||||||
|
httpRoute.parentRefs:
|
||||||
|
- name: my-gateway
|
||||||
|
namespace: gateway-system
|
||||||
|
sectionName: https
|
||||||
|
httpRoute.hostnames:
|
||||||
|
- jellyfin.example.com
|
||||||
|
- media.example.com
|
||||||
|
networkPolicy.enabled: true
|
||||||
|
asserts:
|
||||||
|
- template: httpRoute.yaml
|
||||||
|
hasDocuments:
|
||||||
|
count: 1
|
||||||
|
- template: httpRoute.yaml
|
||||||
|
lengthEqual:
|
||||||
|
path: spec.parentRefs
|
||||||
|
count: 1
|
||||||
|
- template: httpRoute.yaml
|
||||||
|
lengthEqual:
|
||||||
|
path: spec.hostnames
|
||||||
|
count: 2
|
||||||
|
- template: networkpolicy.yaml
|
||||||
|
hasDocuments:
|
||||||
|
count: 1
|
||||||
@@ -0,0 +1,557 @@
|
|||||||
|
suite: test regression defaults
|
||||||
|
templates:
|
||||||
|
- deployment.yaml
|
||||||
|
- service.yaml
|
||||||
|
- serviceaccount.yaml
|
||||||
|
- ingress.yaml
|
||||||
|
- httpRoute.yaml
|
||||||
|
- networkpolicy.yaml
|
||||||
|
- serviceMonitor.yaml
|
||||||
|
- persistentVolumeClaim.yaml
|
||||||
|
tests:
|
||||||
|
# =============================================================================
|
||||||
|
# DEPLOYMENT DEFAULTS
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should have default replica count of 1
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: spec.replicas
|
||||||
|
value: 1
|
||||||
|
|
||||||
|
- it: should use RollingUpdate strategy by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: spec.strategy.type
|
||||||
|
value: RollingUpdate
|
||||||
|
|
||||||
|
- it: should have revisionHistoryLimit of 3 by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: spec.revisionHistoryLimit
|
||||||
|
value: 3
|
||||||
|
|
||||||
|
- it: should use default image jellyfin/jellyfin
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- matchRegex:
|
||||||
|
path: spec.template.spec.containers[0].image
|
||||||
|
pattern: ^jellyfin/jellyfin:
|
||||||
|
|
||||||
|
- it: should use IfNotPresent pullPolicy by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: spec.template.spec.containers[0].imagePullPolicy
|
||||||
|
value: IfNotPresent
|
||||||
|
|
||||||
|
- it: should not have resources set by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNull:
|
||||||
|
path: spec.template.spec.containers[0].resources
|
||||||
|
|
||||||
|
- it: should use ClusterFirst dnsPolicy by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: spec.template.spec.dnsPolicy
|
||||||
|
value: ClusterFirst
|
||||||
|
|
||||||
|
- it: should not enable hostNetwork by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNull:
|
||||||
|
path: spec.template.spec.hostNetwork
|
||||||
|
|
||||||
|
- it: should not have podSecurityContext by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNull:
|
||||||
|
path: spec.template.spec.securityContext
|
||||||
|
|
||||||
|
- it: should not have container securityContext by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNull:
|
||||||
|
path: spec.template.spec.containers[0].securityContext
|
||||||
|
|
||||||
|
- it: should expose port 8096 by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: spec.template.spec.containers[0].ports[0].containerPort
|
||||||
|
value: 8096
|
||||||
|
- equal:
|
||||||
|
path: spec.template.spec.containers[0].ports[0].name
|
||||||
|
value: http
|
||||||
|
|
||||||
|
- it: should have exactly 3 default volumes
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- lengthEqual:
|
||||||
|
path: spec.template.spec.volumes
|
||||||
|
count: 3
|
||||||
|
|
||||||
|
- it: should have config, media, and cache volumes by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- contains:
|
||||||
|
path: spec.template.spec.volumes
|
||||||
|
content:
|
||||||
|
name: config
|
||||||
|
- contains:
|
||||||
|
path: spec.template.spec.volumes
|
||||||
|
content:
|
||||||
|
name: media
|
||||||
|
- contains:
|
||||||
|
path: spec.template.spec.volumes
|
||||||
|
content:
|
||||||
|
name: cache
|
||||||
|
emptyDir: {}
|
||||||
|
|
||||||
|
- it: should mount all three volumes by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- lengthEqual:
|
||||||
|
path: spec.template.spec.containers[0].volumeMounts
|
||||||
|
count: 3
|
||||||
|
- contains:
|
||||||
|
path: spec.template.spec.containers[0].volumeMounts
|
||||||
|
content:
|
||||||
|
name: config
|
||||||
|
mountPath: /config
|
||||||
|
- contains:
|
||||||
|
path: spec.template.spec.containers[0].volumeMounts
|
||||||
|
content:
|
||||||
|
name: media
|
||||||
|
mountPath: /media
|
||||||
|
- contains:
|
||||||
|
path: spec.template.spec.containers[0].volumeMounts
|
||||||
|
content:
|
||||||
|
name: cache
|
||||||
|
mountPath: /cache
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# PROBE DEFAULTS
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should have startup probe by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNotNull:
|
||||||
|
path: spec.template.spec.containers[0].startupProbe
|
||||||
|
|
||||||
|
- it: should use tcpSocket for startup probe by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNotNull:
|
||||||
|
path: spec.template.spec.containers[0].startupProbe.tcpSocket
|
||||||
|
|
||||||
|
- it: should have default startup probe timing
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: spec.template.spec.containers[0].startupProbe.initialDelaySeconds
|
||||||
|
value: 0
|
||||||
|
- equal:
|
||||||
|
path: spec.template.spec.containers[0].startupProbe.periodSeconds
|
||||||
|
value: 10
|
||||||
|
- equal:
|
||||||
|
path: spec.template.spec.containers[0].startupProbe.failureThreshold
|
||||||
|
value: 30
|
||||||
|
|
||||||
|
- it: should have liveness probe by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNotNull:
|
||||||
|
path: spec.template.spec.containers[0].livenessProbe
|
||||||
|
|
||||||
|
- it: should use httpGet for liveness probe by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNotNull:
|
||||||
|
path: spec.template.spec.containers[0].livenessProbe.httpGet
|
||||||
|
- equal:
|
||||||
|
path: spec.template.spec.containers[0].livenessProbe.httpGet.path
|
||||||
|
value: /health
|
||||||
|
|
||||||
|
- it: should have default liveness probe initialDelay of 10
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: spec.template.spec.containers[0].livenessProbe.initialDelaySeconds
|
||||||
|
value: 10
|
||||||
|
|
||||||
|
- it: should have readiness probe by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNotNull:
|
||||||
|
path: spec.template.spec.containers[0].readinessProbe
|
||||||
|
|
||||||
|
- it: should use httpGet for readiness probe by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNotNull:
|
||||||
|
path: spec.template.spec.containers[0].readinessProbe.httpGet
|
||||||
|
- equal:
|
||||||
|
path: spec.template.spec.containers[0].readinessProbe.httpGet.path
|
||||||
|
value: /health
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SERVICE DEFAULTS
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should create Service by default
|
||||||
|
template: service.yaml
|
||||||
|
asserts:
|
||||||
|
- hasDocuments:
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
- it: should use ClusterIP type by default
|
||||||
|
template: service.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: spec.type
|
||||||
|
value: ClusterIP
|
||||||
|
|
||||||
|
- it: should expose port 8096 by default
|
||||||
|
template: service.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: spec.ports[0].port
|
||||||
|
value: 8096
|
||||||
|
- equal:
|
||||||
|
path: spec.ports[0].name
|
||||||
|
value: http
|
||||||
|
|
||||||
|
- it: should not have ipFamilyPolicy set by default
|
||||||
|
template: service.yaml
|
||||||
|
asserts:
|
||||||
|
- isNull:
|
||||||
|
path: spec.ipFamilyPolicy
|
||||||
|
|
||||||
|
- it: should not have ipFamilies set by default
|
||||||
|
template: service.yaml
|
||||||
|
asserts:
|
||||||
|
- isNull:
|
||||||
|
path: spec.ipFamilies
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SERVICEACCOUNT DEFAULTS
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should create ServiceAccount by default
|
||||||
|
template: serviceaccount.yaml
|
||||||
|
asserts:
|
||||||
|
- hasDocuments:
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
- it: should enable automount by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: spec.template.spec.automountServiceAccountToken
|
||||||
|
value: true
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# PERSISTENCE DEFAULTS
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should create config and media PVCs by default
|
||||||
|
template: persistentVolumeClaim.yaml
|
||||||
|
asserts:
|
||||||
|
- hasDocuments:
|
||||||
|
count: 2
|
||||||
|
|
||||||
|
- it: should have config persistence enabled with size 5Gi by default
|
||||||
|
template: persistentVolumeClaim.yaml
|
||||||
|
documentIndex: 0
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: metadata.name
|
||||||
|
value: RELEASE-NAME-jellyfin-config
|
||||||
|
- equal:
|
||||||
|
path: spec.resources.requests.storage
|
||||||
|
value: 5Gi
|
||||||
|
|
||||||
|
- it: should have media persistence enabled with size 25Gi by default
|
||||||
|
template: persistentVolumeClaim.yaml
|
||||||
|
documentIndex: 1
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: metadata.name
|
||||||
|
value: RELEASE-NAME-jellyfin-media
|
||||||
|
- equal:
|
||||||
|
path: spec.resources.requests.storage
|
||||||
|
value: 25Gi
|
||||||
|
|
||||||
|
- it: should use ReadWriteOnce accessMode by default
|
||||||
|
template: persistentVolumeClaim.yaml
|
||||||
|
documentIndex: 0
|
||||||
|
asserts:
|
||||||
|
- contains:
|
||||||
|
path: spec.accessModes
|
||||||
|
content: ReadWriteOnce
|
||||||
|
|
||||||
|
- it: should not create cache PVC by default
|
||||||
|
template: persistentVolumeClaim.yaml
|
||||||
|
asserts:
|
||||||
|
- hasDocuments:
|
||||||
|
count: 2
|
||||||
|
|
||||||
|
- it: should use emptyDir for cache by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- contains:
|
||||||
|
path: spec.template.spec.volumes
|
||||||
|
content:
|
||||||
|
name: cache
|
||||||
|
emptyDir: {}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# OPTIONAL FEATURES DISABLED BY DEFAULT
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should not create Ingress by default
|
||||||
|
template: ingress.yaml
|
||||||
|
asserts:
|
||||||
|
- hasDocuments:
|
||||||
|
count: 0
|
||||||
|
|
||||||
|
- it: should not create HTTPRoute by default
|
||||||
|
template: httpRoute.yaml
|
||||||
|
asserts:
|
||||||
|
- hasDocuments:
|
||||||
|
count: 0
|
||||||
|
|
||||||
|
- it: should not create NetworkPolicy by default
|
||||||
|
template: networkpolicy.yaml
|
||||||
|
asserts:
|
||||||
|
- hasDocuments:
|
||||||
|
count: 0
|
||||||
|
|
||||||
|
- it: should not create ServiceMonitor by default
|
||||||
|
template: serviceMonitor.yaml
|
||||||
|
asserts:
|
||||||
|
- hasDocuments:
|
||||||
|
count: 0
|
||||||
|
|
||||||
|
- it: should not enable DLNA by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNull:
|
||||||
|
path: spec.template.spec.hostNetwork
|
||||||
|
|
||||||
|
- it: should not enable metrics by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNull:
|
||||||
|
path: spec.template.spec.containers[0].lifecycle
|
||||||
|
|
||||||
|
- it: should not have init containers by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNull:
|
||||||
|
path: spec.template.spec.initContainers
|
||||||
|
|
||||||
|
- it: should not have extra containers by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- lengthEqual:
|
||||||
|
path: spec.template.spec.containers
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
- it: should not have imagePullSecrets by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNull:
|
||||||
|
path: spec.template.spec.imagePullSecrets
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# LABEL DEFAULTS
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should have standard Kubernetes labels on deployment
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: metadata.labels.app\.kubernetes\.io/name
|
||||||
|
value: jellyfin
|
||||||
|
- equal:
|
||||||
|
path: metadata.labels.app\.kubernetes\.io/instance
|
||||||
|
value: RELEASE-NAME
|
||||||
|
- isNotNull:
|
||||||
|
path: metadata.labels.app\.kubernetes\.io/version
|
||||||
|
- isNotNull:
|
||||||
|
path: metadata.labels.helm\.sh/chart
|
||||||
|
|
||||||
|
- it: should have standard labels on service
|
||||||
|
template: service.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: metadata.labels.app\.kubernetes\.io/name
|
||||||
|
value: jellyfin
|
||||||
|
- equal:
|
||||||
|
path: metadata.labels.app\.kubernetes\.io/instance
|
||||||
|
value: RELEASE-NAME
|
||||||
|
|
||||||
|
- it: should have standard labels on serviceaccount
|
||||||
|
template: serviceaccount.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: metadata.labels.app\.kubernetes\.io/name
|
||||||
|
value: jellyfin
|
||||||
|
- equal:
|
||||||
|
path: metadata.labels.app\.kubernetes\.io/instance
|
||||||
|
value: RELEASE-NAME
|
||||||
|
|
||||||
|
- it: should have standard labels on PVCs
|
||||||
|
template: persistentVolumeClaim.yaml
|
||||||
|
documentIndex: 0
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: metadata.labels.app\.kubernetes\.io/name
|
||||||
|
value: jellyfin
|
||||||
|
- equal:
|
||||||
|
path: metadata.labels.app\.kubernetes\.io/instance
|
||||||
|
value: RELEASE-NAME
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# API VERSIONS
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should use apps/v1 for Deployment
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: apiVersion
|
||||||
|
value: apps/v1
|
||||||
|
|
||||||
|
- it: should use v1 for Service
|
||||||
|
template: service.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: apiVersion
|
||||||
|
value: v1
|
||||||
|
|
||||||
|
- it: should use v1 for ServiceAccount
|
||||||
|
template: serviceaccount.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: apiVersion
|
||||||
|
value: v1
|
||||||
|
|
||||||
|
- it: should use v1 for PersistentVolumeClaim
|
||||||
|
template: persistentVolumeClaim.yaml
|
||||||
|
documentIndex: 0
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: apiVersion
|
||||||
|
value: v1
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# REGRESSION: VERIFY NO UNEXPECTED CHANGES
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should maintain exactly one container by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- lengthEqual:
|
||||||
|
path: spec.template.spec.containers
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
- it: should maintain container name as jellyfin
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: spec.template.spec.containers[0].name
|
||||||
|
value: jellyfin
|
||||||
|
|
||||||
|
- it: should maintain service name pattern
|
||||||
|
template: service.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: metadata.name
|
||||||
|
value: RELEASE-NAME-jellyfin
|
||||||
|
|
||||||
|
- it: should maintain serviceAccount name pattern
|
||||||
|
template: serviceaccount.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: metadata.name
|
||||||
|
value: RELEASE-NAME-jellyfin
|
||||||
|
|
||||||
|
- it: should maintain deployment name pattern
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: metadata.name
|
||||||
|
value: RELEASE-NAME-jellyfin
|
||||||
|
|
||||||
|
- it: should maintain PVC naming pattern
|
||||||
|
template: persistentVolumeClaim.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: metadata.name
|
||||||
|
documentIndex: 0
|
||||||
|
value: RELEASE-NAME-jellyfin-config
|
||||||
|
- equal:
|
||||||
|
path: metadata.name
|
||||||
|
documentIndex: 1
|
||||||
|
value: RELEASE-NAME-jellyfin-media
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# CRITICAL DEFAULTS THAT MUST NOT CHANGE
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
- it: should never create multiple replicas by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- equal:
|
||||||
|
path: spec.replicas
|
||||||
|
value: 1
|
||||||
|
|
||||||
|
- it: should never enable hostNetwork by default
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNull:
|
||||||
|
path: spec.template.spec.hostNetwork
|
||||||
|
|
||||||
|
- it: should never enable NetworkPolicy by default
|
||||||
|
template: networkpolicy.yaml
|
||||||
|
asserts:
|
||||||
|
- hasDocuments:
|
||||||
|
count: 0
|
||||||
|
|
||||||
|
- it: should always create exactly one service
|
||||||
|
template: service.yaml
|
||||||
|
asserts:
|
||||||
|
- hasDocuments:
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
- it: should always create serviceAccount by default
|
||||||
|
template: serviceaccount.yaml
|
||||||
|
asserts:
|
||||||
|
- hasDocuments:
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
- it: should always have three probes configured
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- isNotNull:
|
||||||
|
path: spec.template.spec.containers[0].startupProbe
|
||||||
|
- isNotNull:
|
||||||
|
path: spec.template.spec.containers[0].livenessProbe
|
||||||
|
- isNotNull:
|
||||||
|
path: spec.template.spec.containers[0].readinessProbe
|
||||||
|
|
||||||
|
- it: should always mount all persistence volumes
|
||||||
|
template: deployment.yaml
|
||||||
|
asserts:
|
||||||
|
- lengthEqual:
|
||||||
|
path: spec.template.spec.containers[0].volumeMounts
|
||||||
|
count: 3
|
||||||
Reference in new issue
Block a user