| /* |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package trait |
| |
| import ( |
| "context" |
| "strings" |
| "testing" |
| |
| passert "github.com/magiconair/properties/assert" |
| "github.com/stretchr/testify/assert" |
| |
| corev1 "k8s.io/api/core/v1" |
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| |
| v1 "github.com/apache/camel-k/pkg/apis/camel/v1" |
| "github.com/apache/camel-k/pkg/util" |
| "github.com/apache/camel-k/pkg/util/camel" |
| k8sutils "github.com/apache/camel-k/pkg/util/kubernetes" |
| "github.com/apache/camel-k/pkg/util/test" |
| ) |
| |
| func TestCronFromURI(t *testing.T) { |
| tests := []struct { |
| uri string |
| uri2 string |
| uri3 string |
| cron string |
| components string |
| }{ |
| // Timer only |
| { |
| uri: "timer:tick?period=60000&delay=12", // invalid |
| }, |
| { |
| uri: "timer:tick?period=60000&repeatCount=10", // invalid |
| }, |
| { |
| uri: "timer:tick?period=60000", |
| cron: "0/1 * * * ?", |
| components: "timer", |
| }, |
| { |
| uri: "timer:tick?period=28800000", |
| cron: "0 0/8 * * ?", |
| components: "timer", |
| }, |
| { |
| uri: "timer:tick?period=120000", |
| cron: "0/2 * * * ?", |
| components: "timer", |
| }, |
| { |
| uri: "timer:tick?period=120001", // invalid |
| }, |
| { |
| uri: "timer:tick?period=60000", |
| cron: "0/1 * * * ?", |
| components: "timer", |
| }, |
| { |
| uri: "timer:tick?period=300000", |
| cron: "0/5 * * * ?", |
| components: "timer", |
| }, |
| { |
| uri: "timer:tick?period=600000", |
| cron: "0/10 * * * ?", |
| components: "timer", |
| }, |
| { |
| uri: "timer:tick?period=66000", // invalid |
| }, |
| { |
| uri: "timer:tick?period=7200000", |
| cron: "0 0/2 * * ?", |
| components: "timer", |
| }, |
| { |
| uri: "timer:tick?period=10800000", |
| cron: "0 0/3 * * ?", |
| components: "timer", |
| }, |
| { |
| uri: "timer:tick?period=86400000", |
| cron: "0 0 * * ?", |
| components: "timer", |
| }, |
| { |
| uri: "timer:tick?period=10860000", // invalid |
| }, |
| { |
| uri: "timer:tick?period=14400000", |
| cron: "0 0/4 * * ?", |
| components: "timer", |
| }, |
| |
| // Quartz only |
| { |
| uri: "quartz:trigger?cron=0 0 0/4 * * ?", |
| cron: "0 0/4 * * ?", |
| components: "quartz", |
| }, |
| { |
| uri: "quartz:trigger?cron=0+0+0/4+*+*+?", |
| cron: "0 0/4 * * ?", |
| components: "quartz", |
| }, |
| { |
| uri: "quartz:trigger?cron=*+0+0/4+*+*+?", // invalid |
| }, |
| { |
| uri: "quartz:trigger?cron=0+0+0/4+*+*+?+2020", // invalid |
| }, |
| { |
| uri: "quartz:trigger?cron=1+0+0/4+*+*+?", // invalid |
| }, |
| { |
| uri: "quartz:trigger?cron=0+0+0/4+*+*+?&fireNow=true", // invalid |
| }, |
| |
| // Cron only |
| { |
| uri: "cron:tab?schedule=1/2 * * * ?", |
| cron: "1/2 * * * ?", |
| components: "cron", |
| }, |
| { |
| uri: "cron:tab?schedule=0 0 0/4 * * ?", |
| cron: "0 0/4 * * ?", |
| components: "cron", |
| }, |
| { |
| uri: "cron:tab?schedule=0+0+0/4+*+*+?", |
| cron: "0 0/4 * * ?", |
| components: "cron", |
| }, |
| { |
| uri: "cron:tab?schedule=*+0+0/4+*+*+?", // invalid |
| }, |
| { |
| uri: "cron:tab?schedule=0+0,6+0/4+*+*+MON-THU", |
| cron: "0,6 0/4 * * MON-THU", |
| components: "cron", |
| }, |
| { |
| uri: "cron:tab?schedule=0+0+0/4+*+*+?+2020", // invalid |
| }, |
| { |
| uri: "cron:tab?schedule=1+0+0/4+*+*+?", // invalid |
| }, |
| |
| // Mixed scenarios |
| { |
| uri: "cron:tab?schedule=0/2 * * * ?", |
| uri2: "timer:tick?period=120000", |
| cron: "0/2 * * * ?", |
| components: "cron,timer", |
| }, |
| { |
| uri: "cron:tab?schedule=0 0/2 * * ?", |
| uri2: "timer:tick?period=7200000", |
| uri3: "quartz:trigger?cron=0 0 0/2 * * ? ?", |
| cron: "0 0/2 * * ?", |
| components: "cron,timer,quartz", |
| }, |
| { |
| uri: "cron:tab?schedule=1 0/2 * * ?", |
| uri2: "timer:tick?period=7200000", |
| uri3: "quartz:trigger?cron=0 0 0/2 * * ? ?", |
| // invalid |
| }, |
| { |
| uri: "cron:tab?schedule=0 0/2 * * ?", |
| uri2: "timer:tick?period=10800000", |
| uri3: "quartz:trigger?cron=0 0 0/2 * * ? ?", |
| // invalid |
| }, |
| } |
| |
| for _, test := range tests { |
| thetest := test |
| t.Run(thetest.uri, func(t *testing.T) { |
| uris := []string{thetest.uri, thetest.uri2, thetest.uri3} |
| filtered := make([]string, 0, len(uris)) |
| for _, uri := range uris { |
| if uri != "" { |
| filtered = append(filtered, uri) |
| } |
| } |
| |
| res := getCronForURIs(filtered) |
| gotCron := "" |
| if res != nil { |
| gotCron = res.schedule |
| } |
| passert.Equal(t, gotCron, thetest.cron) |
| |
| gotComponents := "" |
| if res != nil { |
| gotComponents = strings.Join(res.components, ",") |
| } |
| passert.Equal(t, gotComponents, thetest.components) |
| }) |
| } |
| } |
| |
| func TestCronDeps(t *testing.T) { |
| catalog, err := camel.DefaultCatalog() |
| assert.Nil(t, err) |
| |
| traitCatalog := NewCatalog(context.TODO(), nil) |
| |
| environment := Environment{ |
| CamelCatalog: catalog, |
| Catalog: traitCatalog, |
| Integration: &v1.Integration{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: "test", |
| Namespace: "ns", |
| }, |
| Status: v1.IntegrationStatus{ |
| Phase: v1.IntegrationPhaseInitialization, |
| }, |
| Spec: v1.IntegrationSpec{ |
| Profile: v1.TraitProfileKnative, |
| Sources: []v1.SourceSpec{ |
| { |
| DataSpec: v1.DataSpec{ |
| Name: "routes.java", |
| Content: `from("cron:tab?schedule=0 0/2 * * ?").to("log:test")`, |
| }, |
| Language: v1.LanguageJavaSource, |
| }, |
| }, |
| Resources: []v1.ResourceSpec{}, |
| Traits: map[string]v1.TraitSpec{}, |
| }, |
| }, |
| IntegrationKit: &v1.IntegrationKit{ |
| Status: v1.IntegrationKitStatus{ |
| Phase: v1.IntegrationKitPhaseReady, |
| }, |
| }, |
| Platform: &v1.IntegrationPlatform{ |
| Spec: v1.IntegrationPlatformSpec{ |
| Cluster: v1.IntegrationPlatformClusterOpenShift, |
| Build: v1.IntegrationPlatformBuildSpec{ |
| PublishStrategy: v1.IntegrationPlatformBuildPublishStrategyS2I, |
| Registry: v1.IntegrationPlatformRegistrySpec{Address: "registry"}, |
| }, |
| Profile: v1.TraitProfileKnative, |
| }, |
| }, |
| EnvVars: make([]corev1.EnvVar, 0), |
| ExecutedTraits: make([]Trait, 0), |
| Resources: k8sutils.NewCollection(), |
| } |
| environment.Platform.ResyncStatusFullConfig() |
| |
| c, err := NewFakeClient("ns") |
| assert.Nil(t, err) |
| |
| tc := NewCatalog(context.TODO(), c) |
| |
| err = tc.apply(&environment) |
| |
| assert.Nil(t, err) |
| assert.NotEmpty(t, environment.ExecutedTraits) |
| |
| ct := environment.GetTrait("cron").(*cronTrait) |
| assert.NotNil(t, ct) |
| assert.Nil(t, ct.Fallback) |
| assert.True(t, util.StringSliceExists(environment.Integration.Status.Capabilities, v1.CapabilityCron)) |
| assert.Contains(t, environment.Integration.Status.Dependencies, "mvn:org.apache.camel.k/camel-k-runtime-cron") |
| } |
| |
| func TestCronDepsFallback(t *testing.T) { |
| catalog, err := camel.DefaultCatalog() |
| assert.Nil(t, err) |
| |
| traitCatalog := NewCatalog(context.TODO(), nil) |
| |
| environment := Environment{ |
| CamelCatalog: catalog, |
| Catalog: traitCatalog, |
| Integration: &v1.Integration{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: "test", |
| Namespace: "ns", |
| }, |
| Status: v1.IntegrationStatus{ |
| Phase: v1.IntegrationPhaseInitialization, |
| }, |
| Spec: v1.IntegrationSpec{ |
| Profile: v1.TraitProfileKnative, |
| Sources: []v1.SourceSpec{ |
| { |
| DataSpec: v1.DataSpec{ |
| Name: "routes.java", |
| Content: `from("cron:tab?schedule=0 0/2 * * ?").to("log:test")`, |
| }, |
| Language: v1.LanguageJavaSource, |
| }, |
| }, |
| Resources: []v1.ResourceSpec{}, |
| Traits: map[string]v1.TraitSpec{ |
| "cron": test.TraitSpecFromMap(t, map[string]interface{}{ |
| "fallback": true, |
| }), |
| }, |
| }, |
| }, |
| IntegrationKit: &v1.IntegrationKit{ |
| Status: v1.IntegrationKitStatus{ |
| Phase: v1.IntegrationKitPhaseReady, |
| }, |
| }, |
| Platform: &v1.IntegrationPlatform{ |
| Spec: v1.IntegrationPlatformSpec{ |
| Cluster: v1.IntegrationPlatformClusterOpenShift, |
| Build: v1.IntegrationPlatformBuildSpec{ |
| PublishStrategy: v1.IntegrationPlatformBuildPublishStrategyS2I, |
| Registry: v1.IntegrationPlatformRegistrySpec{Address: "registry"}, |
| }, |
| Profile: v1.TraitProfileKnative, |
| }, |
| }, |
| EnvVars: make([]corev1.EnvVar, 0), |
| ExecutedTraits: make([]Trait, 0), |
| Resources: k8sutils.NewCollection(), |
| } |
| environment.Platform.ResyncStatusFullConfig() |
| |
| c, err := NewFakeClient("ns") |
| assert.Nil(t, err) |
| |
| tc := NewCatalog(context.TODO(), c) |
| |
| err = tc.apply(&environment) |
| |
| assert.Nil(t, err) |
| assert.NotEmpty(t, environment.ExecutedTraits) |
| |
| ct := environment.GetTrait("cron").(*cronTrait) |
| assert.NotNil(t, ct) |
| assert.NotNil(t, ct.Fallback) |
| assert.True(t, util.StringSliceExists(environment.Integration.Status.Capabilities, v1.CapabilityCron)) |
| assert.Contains(t, environment.Integration.Status.Dependencies, "camel:quartz") |
| assert.Contains(t, environment.Integration.Status.Dependencies, "mvn:org.apache.camel.k/camel-k-runtime-cron") |
| } |
| |
| func TestCronWithMain(t *testing.T) { |
| catalog, err := camel.DefaultCatalog() |
| assert.Nil(t, err) |
| |
| traitCatalog := NewCatalog(context.TODO(), nil) |
| |
| environment := Environment{ |
| CamelCatalog: catalog, |
| Catalog: traitCatalog, |
| Integration: &v1.Integration{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: "test", |
| Namespace: "ns", |
| }, |
| Status: v1.IntegrationStatus{ |
| Phase: v1.IntegrationPhaseDeploying, |
| }, |
| Spec: v1.IntegrationSpec{ |
| Profile: v1.TraitProfileKnative, |
| Sources: []v1.SourceSpec{ |
| { |
| DataSpec: v1.DataSpec{ |
| Name: "routes.java", |
| Content: `from("cron:tab?schedule=0 0/2 * * ?").to("log:test")`, |
| }, |
| Language: v1.LanguageJavaSource, |
| }, |
| }, |
| Resources: []v1.ResourceSpec{}, |
| Traits: map[string]v1.TraitSpec{ |
| "quarkus": test.TraitSpecFromMap(t, map[string]interface{}{ |
| "enabled": false, |
| }), |
| }, |
| }, |
| }, |
| IntegrationKit: &v1.IntegrationKit{ |
| Status: v1.IntegrationKitStatus{ |
| Phase: v1.IntegrationKitPhaseReady, |
| }, |
| }, |
| Platform: &v1.IntegrationPlatform{ |
| Spec: v1.IntegrationPlatformSpec{ |
| Cluster: v1.IntegrationPlatformClusterOpenShift, |
| Build: v1.IntegrationPlatformBuildSpec{ |
| PublishStrategy: v1.IntegrationPlatformBuildPublishStrategyS2I, |
| Registry: v1.IntegrationPlatformRegistrySpec{Address: "registry"}, |
| }, |
| Profile: v1.TraitProfileKnative, |
| }, |
| }, |
| EnvVars: make([]corev1.EnvVar, 0), |
| ExecutedTraits: make([]Trait, 0), |
| Resources: k8sutils.NewCollection(), |
| } |
| environment.Platform.ResyncStatusFullConfig() |
| |
| c, err := NewFakeClient("ns") |
| assert.Nil(t, err) |
| |
| tc := NewCatalog(context.TODO(), c) |
| |
| err = tc.apply(&environment) |
| |
| assert.Nil(t, err) |
| assert.NotEmpty(t, environment.ExecutedTraits) |
| assert.Nil(t, environment.GetTrait("quarkus")) |
| |
| ct := environment.GetTrait("cron").(*cronTrait) |
| assert.NotNil(t, ct) |
| assert.Nil(t, ct.Fallback) |
| assert.Contains(t, environment.Interceptors, "cron") |
| } |
| |
| func TestCronWithQuarkus(t *testing.T) { |
| catalog, err := camel.DefaultCatalog() |
| assert.Nil(t, err) |
| |
| traitCatalog := NewCatalog(context.TODO(), nil) |
| |
| environment := Environment{ |
| CamelCatalog: catalog, |
| Catalog: traitCatalog, |
| Integration: &v1.Integration{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: "test", |
| Namespace: "ns", |
| }, |
| Status: v1.IntegrationStatus{ |
| Phase: v1.IntegrationPhaseDeploying, |
| }, |
| Spec: v1.IntegrationSpec{ |
| Profile: v1.TraitProfileKnative, |
| Sources: []v1.SourceSpec{ |
| { |
| DataSpec: v1.DataSpec{ |
| Name: "routes.java", |
| Content: `from("cron:tab?schedule=0 0/2 * * ?").to("log:test")`, |
| }, |
| Language: v1.LanguageJavaSource, |
| }, |
| }, |
| Resources: []v1.ResourceSpec{}, |
| Traits: map[string]v1.TraitSpec{ |
| "quarkus": test.TraitSpecFromMap(t, map[string]interface{}{ |
| "enabled": true, |
| }), |
| }, |
| }, |
| }, |
| IntegrationKit: &v1.IntegrationKit{ |
| Status: v1.IntegrationKitStatus{ |
| Phase: v1.IntegrationKitPhaseReady, |
| }, |
| }, |
| Platform: &v1.IntegrationPlatform{ |
| Spec: v1.IntegrationPlatformSpec{ |
| Cluster: v1.IntegrationPlatformClusterOpenShift, |
| Build: v1.IntegrationPlatformBuildSpec{ |
| PublishStrategy: v1.IntegrationPlatformBuildPublishStrategyS2I, |
| Registry: v1.IntegrationPlatformRegistrySpec{Address: "registry"}, |
| }, |
| Profile: v1.TraitProfileKnative, |
| }, |
| }, |
| EnvVars: make([]corev1.EnvVar, 0), |
| ExecutedTraits: make([]Trait, 0), |
| Resources: k8sutils.NewCollection(), |
| } |
| environment.Platform.ResyncStatusFullConfig() |
| |
| c, err := NewFakeClient("ns") |
| assert.Nil(t, err) |
| |
| tc := NewCatalog(context.TODO(), c) |
| |
| err = tc.apply(&environment) |
| |
| assert.Nil(t, err) |
| assert.NotEmpty(t, environment.ExecutedTraits) |
| assert.NotNil(t, environment.GetTrait("quarkus")) |
| |
| ct := environment.GetTrait("cron").(*cronTrait) |
| assert.NotNil(t, ct) |
| assert.Nil(t, ct.Fallback) |
| assert.Contains(t, environment.Interceptors, "cron") |
| } |