| // 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 ingress |
| |
| import ( |
| "encoding/json" |
| "net/http" |
| "time" |
| |
| "github.com/onsi/ginkgo" |
| "github.com/stretchr/testify/assert" |
| |
| "github.com/apache/apisix-ingress-controller/test/e2e/scaffold" |
| ) |
| |
| type ip struct { |
| IP string `json:"ip"` |
| } |
| |
| var _ = ginkgo.Describe("single-route", func() { |
| s := scaffold.NewDefaultScaffold() |
| ginkgo.It("/ip should return your ip", func() { |
| backendSvc, backendSvcPort := s.DefaultHTTPBackend() |
| s.CreateApisixRoute("httpbin-route", []scaffold.ApisixRouteRule{ |
| { |
| Host: "httpbin.com", |
| HTTP: scaffold.ApisixRouteRuleHTTP{ |
| Paths: []scaffold.ApisixRouteRuleHTTPPath{ |
| { |
| Path: "/ip", |
| Backend: scaffold.ApisixRouteRuleHTTPBackend{ |
| ServiceName: backendSvc, |
| ServicePort: backendSvcPort[0], |
| }, |
| }, |
| }, |
| }, |
| }, |
| }) |
| err := s.EnsureNumApisixRoutesCreated(1) |
| assert.Nil(ginkgo.GinkgoT(), err, "checking number of routes") |
| err = s.EnsureNumApisixUpstreamsCreated(1) |
| assert.Nil(ginkgo.GinkgoT(), err, "checking number of upstreams") |
| |
| // TODO When ingress controller can feedback the lifecycle of CRDs to the |
| // status field, we can poll it rather than sleeping. |
| time.Sleep(3 * time.Second) |
| |
| body := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.com").Expect().Status(http.StatusOK).Body().Raw() |
| var placeholder ip |
| err = json.Unmarshal([]byte(body), &placeholder) |
| assert.Nil(ginkgo.GinkgoT(), err, "unmarshalling IP") |
| // It's not our focus point to check the IP address returned by httpbin, |
| // so here skip the IP address validation. |
| }) |
| }) |
| |
| var _ = ginkgo.Describe("double-routes", func() { |
| s := scaffold.NewDefaultScaffold() |
| ginkgo.It("double routes work independently", func() { |
| backendSvc, backendSvcPort := s.DefaultHTTPBackend() |
| s.CreateApisixRoute("httpbin-route", []scaffold.ApisixRouteRule{ |
| { |
| Host: "httpbin.com", |
| HTTP: scaffold.ApisixRouteRuleHTTP{ |
| Paths: []scaffold.ApisixRouteRuleHTTPPath{ |
| { |
| Path: "/ip", |
| Backend: scaffold.ApisixRouteRuleHTTPBackend{ |
| ServiceName: backendSvc, |
| ServicePort: backendSvcPort[0], |
| }, |
| }, |
| { |
| Path: "/json", |
| Backend: scaffold.ApisixRouteRuleHTTPBackend{ |
| ServiceName: backendSvc, |
| ServicePort: backendSvcPort[0], |
| }, |
| }, |
| }, |
| }, |
| }, |
| }) |
| err := s.EnsureNumApisixRoutesCreated(2) |
| assert.Nil(ginkgo.GinkgoT(), err, "checking number of routes") |
| err = s.EnsureNumApisixUpstreamsCreated(1) |
| assert.Nil(ginkgo.GinkgoT(), err, "checking number of upstreams") |
| // TODO When ingress controller can feedback the lifecycle of CRDs to the |
| // status field, we can poll it rather than sleeping. |
| time.Sleep(3 * time.Second) |
| body := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.com").Expect().Status(http.StatusOK).Body().Raw() |
| var placeholder ip |
| err = json.Unmarshal([]byte(body), &placeholder) |
| assert.Nil(ginkgo.GinkgoT(), err, "unmarshalling IP") |
| |
| body = s.NewAPISIXClient().GET("/json").WithHeader("Host", "httpbin.com").Expect().Status(http.StatusOK).Body().Raw() |
| var dummy map[string]interface{} |
| err = json.Unmarshal([]byte(body), &dummy) |
| assert.Nil(ginkgo.GinkgoT(), err, "unmarshalling json") |
| // We don't care the json data, only make sure it's a normal json string. |
| }) |
| }) |
| |
| var _ = ginkgo.Describe("leader election", func() { |
| s := scaffold.NewScaffold(&scaffold.Options{ |
| Name: "leaderelection", |
| Kubeconfig: scaffold.GetKubeconfig(), |
| APISIXConfigPath: "testdata/apisix-gw-config.yaml", |
| APISIXDefaultConfigPath: "testdata/apisix-gw-config-default.yaml", |
| IngressAPISIXReplicas: 2, |
| }) |
| ginkgo.It("lease check", func() { |
| pods, err := s.GetIngressPodDetails() |
| assert.Nil(ginkgo.GinkgoT(), err) |
| assert.Len(ginkgo.GinkgoT(), pods, 2) |
| lease, err := s.WaitGetLeaderLease() |
| assert.Nil(ginkgo.GinkgoT(), err) |
| assert.Equal(ginkgo.GinkgoT(), *lease.Spec.LeaseDurationSeconds, int32(15)) |
| if *lease.Spec.HolderIdentity != pods[0].Name && *lease.Spec.HolderIdentity != pods[1].Name { |
| assert.Fail(ginkgo.GinkgoT(), "bad leader lease holder identity") |
| } |
| }) |
| |
| ginkgo.It("leader failover", func() { |
| pods, err := s.GetIngressPodDetails() |
| assert.Nil(ginkgo.GinkgoT(), err) |
| assert.Len(ginkgo.GinkgoT(), pods, 2) |
| |
| lease, err := s.WaitGetLeaderLease() |
| assert.Nil(ginkgo.GinkgoT(), err) |
| |
| leaderIdx := 0 |
| if *lease.Spec.HolderIdentity == pods[1].Name { |
| leaderIdx = 1 |
| } |
| ginkgo.GinkgoT().Logf("lease is %s", *lease.Spec.HolderIdentity) |
| assert.Nil(ginkgo.GinkgoT(), s.KillPod(pods[leaderIdx].Name)) |
| |
| // Wait the old lease expire and new leader was elected. |
| time.Sleep(25 * time.Second) |
| |
| newLease, err := s.WaitGetLeaderLease() |
| assert.Nil(ginkgo.GinkgoT(), err) |
| |
| newPods, err := s.GetIngressPodDetails() |
| assert.Nil(ginkgo.GinkgoT(), err) |
| assert.Len(ginkgo.GinkgoT(), pods, 2) |
| |
| assert.NotEqual(ginkgo.GinkgoT(), *newLease.Spec.HolderIdentity, *lease.Spec.HolderIdentity) |
| assert.Greater(ginkgo.GinkgoT(), *newLease.Spec.LeaseTransitions, *lease.Spec.LeaseTransitions) |
| |
| if *newLease.Spec.HolderIdentity != newPods[0].Name && *newLease.Spec.HolderIdentity != newPods[1].Name { |
| assert.Failf(ginkgo.GinkgoT(), "bad leader lease holder identity: %s, should be %s or %s", |
| *newLease.Spec.HolderIdentity, newPods[0].Name, newPods[1].Name) |
| } |
| }) |
| }) |