mirror of
https://github.com/ngrok/ngrok-operator.git
synced 2026-05-17 16:50:44 +00:00
aa1781d348
* chore: Update to go 1.26.1 Signed-off-by: Jonathan Stacks <jonstacks@users.noreply.github.com> * chore: Run 'go fix ./...' for go 1.26.1 Signed-off-by: Jonathan Stacks <jonstacks@users.noreply.github.com> * chore: Upgrade go modules Signed-off-by: Jonathan Stacks <jonstacks@users.noreply.github.com> * chore: Fix deprecations and linter warnings Signed-off-by: Jonathan Stacks <jonstacks@users.noreply.github.com> --------- Signed-off-by: Jonathan Stacks <jonstacks@users.noreply.github.com>
387 lines
9.9 KiB
Go
387 lines
9.9 KiB
Go
package testutils
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
ingressv1alpha1 "github.com/ngrok/ngrok-operator/api/ingress/v1alpha1"
|
|
ngrokv1alpha1 "github.com/ngrok/ngrok-operator/api/ngrok/v1alpha1"
|
|
corev1 "k8s.io/api/core/v1"
|
|
netv1 "k8s.io/api/networking/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/util/intstr"
|
|
"k8s.io/apimachinery/pkg/util/rand"
|
|
"k8s.io/utils/ptr"
|
|
|
|
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
|
|
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
|
|
gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
|
|
)
|
|
|
|
func NewTestIngressClass(name string, isDefault bool, isNgrok bool) *netv1.IngressClass {
|
|
i := netv1.IngressClass{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Labels: map[string]string{
|
|
"app.kubernetes.io/component": "controller",
|
|
},
|
|
},
|
|
}
|
|
|
|
if isNgrok {
|
|
i.Spec.Controller = "k8s.ngrok.com/ingress-controller"
|
|
} else {
|
|
i.Spec.Controller = "kubernetes.io/ingress-other"
|
|
}
|
|
|
|
if isDefault {
|
|
i.Annotations = map[string]string{
|
|
"ingressclass.kubernetes.io/is-default-class": "true", // TODO: Move this into a utility for ingress classes
|
|
}
|
|
}
|
|
|
|
return &i
|
|
}
|
|
|
|
func NewTestIngressV1WithClass(name string, namespace string, ingressClass string) *netv1.Ingress {
|
|
i := NewTestIngressV1(name, namespace)
|
|
i.Spec.IngressClassName = &ingressClass
|
|
return i
|
|
}
|
|
|
|
// NewTestIngressV1WithHosts creates an ingress with the specified hosts.
|
|
func NewTestIngressV1WithHosts(name string, namespace string, hosts ...string) *netv1.Ingress {
|
|
rules := make([]netv1.IngressRule, 0, len(hosts))
|
|
for _, host := range hosts {
|
|
rules = append(rules, netv1.IngressRule{
|
|
Host: host,
|
|
IngressRuleValue: netv1.IngressRuleValue{
|
|
HTTP: &netv1.HTTPIngressRuleValue{
|
|
Paths: []netv1.HTTPIngressPath{
|
|
{
|
|
Path: "/",
|
|
Backend: netv1.IngressBackend{
|
|
Service: &netv1.IngressServiceBackend{
|
|
Name: "example",
|
|
Port: netv1.ServiceBackendPort{
|
|
Number: 80,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
return &netv1.Ingress{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace,
|
|
},
|
|
Spec: netv1.IngressSpec{
|
|
Rules: rules,
|
|
},
|
|
}
|
|
}
|
|
|
|
func NewTestIngressV1(name string, namespace string) *netv1.Ingress {
|
|
return NewTestIngressV1WithHosts(name, namespace, "example.com")
|
|
}
|
|
|
|
func NewTestServiceV1(name string, namespace string) *corev1.Service {
|
|
return &corev1.Service{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace,
|
|
},
|
|
Spec: corev1.ServiceSpec{
|
|
Ports: []corev1.ServicePort{
|
|
{
|
|
Name: "http",
|
|
Protocol: "TCP",
|
|
Port: 80,
|
|
TargetPort: intstr.FromString("http"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
type DomainOpt func(*ingressv1alpha1.Domain)
|
|
|
|
// WithDomainStatusCondition adds a condition to the domain's status.
|
|
func WithDomainStatusCondition(condition metav1.Condition) DomainOpt {
|
|
return func(d *ingressv1alpha1.Domain) {
|
|
d.Status.Conditions = append(d.Status.Conditions, condition)
|
|
}
|
|
}
|
|
|
|
// WithDomainReadyCondition is a convenience helper that sets the Ready condition.
|
|
func WithDomainReadyCondition(status metav1.ConditionStatus, message string) DomainOpt {
|
|
return WithDomainStatusCondition(metav1.Condition{
|
|
Type: "Ready",
|
|
Status: status,
|
|
Message: message,
|
|
})
|
|
}
|
|
|
|
func NewDomainV1(name string, namespace string, opts ...DomainOpt) *ingressv1alpha1.Domain {
|
|
d := &ingressv1alpha1.Domain{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: ingressv1alpha1.HyphenatedDomainNameFromURL(name),
|
|
Namespace: namespace,
|
|
},
|
|
Spec: ingressv1alpha1.DomainSpec{
|
|
Domain: name,
|
|
},
|
|
}
|
|
for _, opt := range opts {
|
|
opt(d)
|
|
}
|
|
return d
|
|
}
|
|
|
|
// RandomName generates a random name with the given prefix. The random part is 5 characters long.
|
|
// This is useful for generating unique names for resources in tests.
|
|
func RandomName(prefix string) string {
|
|
return prefix + "-" + rand.String(5)
|
|
}
|
|
|
|
// RandomURL generates a random URL.
|
|
func RandomURL() string {
|
|
return "https://" + RandomName("test-url") + ".ngrok.io"
|
|
}
|
|
|
|
// NewGatewayClass creates a new GatewayClass with a random name to be used in tests. If
|
|
// isManaged is true, the controller name will be set to the ngrok gateway controller name.
|
|
// If isManaged is false, the controller name will be set to a different value.
|
|
func NewGatewayClass(isManaged bool) *gatewayv1.GatewayClass {
|
|
var controllerName gatewayv1.GatewayController = "ngrok.com/gateway-controller"
|
|
if !isManaged {
|
|
controllerName = "k8s.io/some-other-controller"
|
|
}
|
|
return &gatewayv1.GatewayClass{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: RandomName("gateway-class"),
|
|
},
|
|
Spec: gatewayv1.GatewayClassSpec{
|
|
ControllerName: controllerName,
|
|
},
|
|
}
|
|
}
|
|
|
|
func NewGateway(name string, namespace string) gatewayv1.Gateway {
|
|
return gatewayv1.Gateway{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace,
|
|
},
|
|
Spec: gatewayv1.GatewaySpec{
|
|
GatewayClassName: "test-gatewayclass",
|
|
Listeners: []gatewayv1.Listener{
|
|
{
|
|
Hostname: ptr.To(gatewayv1.Hostname("example.com")),
|
|
Name: "http",
|
|
Port: 80,
|
|
Protocol: gatewayv1.HTTPProtocolType,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewGatewayWithHostnames creates a Gateway with the specified hostnames as listeners.
|
|
func NewGatewayWithHostnames(name string, namespace string, hostnames ...string) *gatewayv1.Gateway {
|
|
listeners := make([]gatewayv1.Listener, len(hostnames))
|
|
for i, hostname := range hostnames {
|
|
h := gatewayv1.Hostname(hostname)
|
|
listeners[i] = gatewayv1.Listener{
|
|
Name: gatewayv1.SectionName(fmt.Sprintf("listener-%d", i)),
|
|
Hostname: &h,
|
|
Port: 443,
|
|
Protocol: gatewayv1.HTTPSProtocolType,
|
|
}
|
|
}
|
|
|
|
return &gatewayv1.Gateway{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace,
|
|
},
|
|
Spec: gatewayv1.GatewaySpec{
|
|
GatewayClassName: "ngrok",
|
|
Listeners: listeners,
|
|
},
|
|
}
|
|
}
|
|
|
|
func NewHTTPRoute(name string, namespace string) gatewayv1.HTTPRoute {
|
|
return gatewayv1.HTTPRoute{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace,
|
|
},
|
|
Spec: gatewayv1.HTTPRouteSpec{
|
|
Rules: []gatewayv1.HTTPRouteRule{
|
|
{
|
|
Matches: []gatewayv1.HTTPRouteMatch{
|
|
{
|
|
Path: &gatewayv1.HTTPPathMatch{
|
|
Type: ptr.To(gatewayv1.PathMatchPathPrefix),
|
|
Value: new("/"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func NewTLSRoute(name string, namespace string) gatewayv1alpha2.TLSRoute {
|
|
return gatewayv1alpha2.TLSRoute{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace,
|
|
},
|
|
Spec: gatewayv1alpha2.TLSRouteSpec{
|
|
Rules: []gatewayv1alpha2.TLSRouteRule{
|
|
{
|
|
BackendRefs: []gatewayv1alpha2.BackendRef{
|
|
{
|
|
BackendObjectReference: gatewayv1alpha2.BackendObjectReference{
|
|
Name: "test-service",
|
|
Port: ptr.To(gatewayv1.PortNumber(8000)),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func NewTCPRoute(name string, namespace string) gatewayv1alpha2.TCPRoute {
|
|
return gatewayv1alpha2.TCPRoute{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace,
|
|
},
|
|
Spec: gatewayv1alpha2.TCPRouteSpec{
|
|
Rules: []gatewayv1alpha2.TCPRouteRule{
|
|
{
|
|
BackendRefs: []gatewayv1alpha2.BackendRef{
|
|
{
|
|
BackendObjectReference: gatewayv1alpha2.BackendObjectReference{
|
|
Name: "tcp-service",
|
|
Port: ptr.To(gatewayv1.PortNumber(8000)),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func NewReferenceGrant(name string, namespace string) gatewayv1beta1.ReferenceGrant {
|
|
return gatewayv1beta1.ReferenceGrant{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace,
|
|
},
|
|
Spec: gatewayv1beta1.ReferenceGrantSpec{
|
|
From: []gatewayv1beta1.ReferenceGrantFrom{
|
|
{
|
|
Group: "gateway.networking.k8s.io",
|
|
Kind: "HTTPRoute",
|
|
Namespace: gatewayv1beta1.Namespace("other-namespace"),
|
|
},
|
|
},
|
|
To: []gatewayv1beta1.ReferenceGrantTo{
|
|
{
|
|
Group: "core",
|
|
Kind: "Service",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func NewTestNgrokTrafficPolicy(name string, namespace string, policyStr string) ngrokv1alpha1.NgrokTrafficPolicy {
|
|
return ngrokv1alpha1.NgrokTrafficPolicy{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: namespace,
|
|
},
|
|
Spec: ngrokv1alpha1.NgrokTrafficPolicySpec{
|
|
Policy: json.RawMessage(policyStr),
|
|
},
|
|
}
|
|
}
|
|
|
|
type CloudEndpointOpt func(*ngrokv1alpha1.CloudEndpoint)
|
|
|
|
// NewCloudEndpoint creates a new CloudEndpoint with the given name and namespace.
|
|
// The URL is set to a random name for testing purposes.
|
|
// You can pass additional options to customize the CloudEndpoint further.
|
|
// Example usage:
|
|
//
|
|
// NewCloudEndpoint
|
|
func NewCloudEndpoint(opts ...CloudEndpointOpt) *ngrokv1alpha1.CloudEndpoint {
|
|
clep := &ngrokv1alpha1.CloudEndpoint{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: RandomName("cloud-endpoint"),
|
|
Namespace: RandomName("namespace"),
|
|
},
|
|
Spec: ngrokv1alpha1.CloudEndpointSpec{
|
|
URL: RandomName("url"),
|
|
},
|
|
}
|
|
for _, opt := range opts {
|
|
opt(clep)
|
|
}
|
|
return clep
|
|
}
|
|
|
|
type AgentEndpointOpt func(*ngrokv1alpha1.AgentEndpoint)
|
|
|
|
func NewAgentEndpoint(opts ...AgentEndpointOpt) *ngrokv1alpha1.AgentEndpoint {
|
|
aep := &ngrokv1alpha1.AgentEndpoint{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: RandomName("agent-endpoint"),
|
|
Namespace: RandomName("namespace"),
|
|
},
|
|
Spec: ngrokv1alpha1.AgentEndpointSpec{
|
|
URL: RandomURL(),
|
|
},
|
|
}
|
|
|
|
for _, opt := range opts {
|
|
opt(aep)
|
|
}
|
|
return aep
|
|
}
|
|
|
|
// FindCondition finds a condition by type in a list of conditions.
|
|
// Returns nil if the condition is not found.
|
|
func FindCondition(conditions []metav1.Condition, condType string) *metav1.Condition {
|
|
for i := range conditions {
|
|
if conditions[i].Type == condType {
|
|
return &conditions[i]
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// NewDomainMap creates a map of domain name to Domain objects, useful for testing
|
|
// functions that operate on domain lookups.
|
|
func NewDomainMap(domains ...*ingressv1alpha1.Domain) map[string]ingressv1alpha1.Domain {
|
|
result := make(map[string]ingressv1alpha1.Domain, len(domains))
|
|
for _, d := range domains {
|
|
result[d.Spec.Domain] = *d
|
|
}
|
|
return result
|
|
}
|