helper_test.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. package clustercache
  2. import (
  3. "testing"
  4. v1 "k8s.io/api/core/v1"
  5. )
  6. func TestGetLoadBalancerIngressAddress(t *testing.T) {
  7. tests := []struct {
  8. name string
  9. service *Service
  10. expected []string
  11. }{
  12. {
  13. name: "no ingresses",
  14. service: &Service{},
  15. expected: nil,
  16. },
  17. {
  18. name: "single IP ingress",
  19. service: &Service{
  20. Status: v1.ServiceStatus{
  21. LoadBalancer: v1.LoadBalancerStatus{
  22. Ingress: []v1.LoadBalancerIngress{
  23. {IP: "1.2.3.4"},
  24. },
  25. },
  26. },
  27. },
  28. expected: []string{"1.2.3.4"},
  29. },
  30. {
  31. name: "single hostname ingress",
  32. service: &Service{
  33. Status: v1.ServiceStatus{
  34. LoadBalancer: v1.LoadBalancerStatus{
  35. Ingress: []v1.LoadBalancerIngress{
  36. {Hostname: "lb.example.com"},
  37. },
  38. },
  39. },
  40. },
  41. expected: []string{"lb.example.com"},
  42. },
  43. {
  44. name: "IP takes priority over hostname",
  45. service: &Service{
  46. Status: v1.ServiceStatus{
  47. LoadBalancer: v1.LoadBalancerStatus{
  48. Ingress: []v1.LoadBalancerIngress{
  49. {IP: "1.2.3.4", Hostname: "lb.example.com"},
  50. },
  51. },
  52. },
  53. },
  54. expected: []string{"1.2.3.4"},
  55. },
  56. {
  57. name: "multiple ingresses",
  58. service: &Service{
  59. Status: v1.ServiceStatus{
  60. LoadBalancer: v1.LoadBalancerStatus{
  61. Ingress: []v1.LoadBalancerIngress{
  62. {IP: "1.2.3.4"},
  63. {Hostname: "lb2.example.com"},
  64. {IP: "5.6.7.8"},
  65. },
  66. },
  67. },
  68. },
  69. expected: []string{"1.2.3.4", "lb2.example.com", "5.6.7.8"},
  70. },
  71. }
  72. for _, tt := range tests {
  73. t.Run(tt.name, func(t *testing.T) {
  74. got := GetLoadBalancerIngressAddress(tt.service)
  75. if len(got) != len(tt.expected) {
  76. t.Fatalf("got %v, want %v", got, tt.expected)
  77. }
  78. for i := range tt.expected {
  79. if got[i] != tt.expected[i] {
  80. t.Errorf("index %d: got %q, want %q", i, got[i], tt.expected[i])
  81. }
  82. }
  83. })
  84. }
  85. }
  86. func Test_getPVProviderID(t *testing.T) {
  87. tests := []struct {
  88. name string
  89. pv *PersistentVolume
  90. want string
  91. }{
  92. {
  93. name: "gce persistent disk uses pd name",
  94. pv: &PersistentVolume{
  95. Name: "pv-gce",
  96. Spec: v1.PersistentVolumeSpec{
  97. PersistentVolumeSource: v1.PersistentVolumeSource{
  98. GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{PDName: "gke-pd-1"},
  99. },
  100. },
  101. },
  102. want: "gke-pd-1",
  103. },
  104. {
  105. name: "azure disk uses disk name",
  106. pv: &PersistentVolume{
  107. Name: "pv-azure",
  108. Spec: v1.PersistentVolumeSpec{
  109. PersistentVolumeSource: v1.PersistentVolumeSource{
  110. AzureDisk: &v1.AzureDiskVolumeSource{DiskName: "azure-disk-1"},
  111. },
  112. },
  113. },
  114. want: "azure-disk-1",
  115. },
  116. {
  117. name: "aws ebs with aws:// prefixed volume id is parsed",
  118. pv: &PersistentVolume{
  119. Name: "pv-aws",
  120. Spec: v1.PersistentVolumeSpec{
  121. PersistentVolumeSource: v1.PersistentVolumeSource{
  122. AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{
  123. VolumeID: "aws://us-east-2a/vol-0fc54c5e83b8d2b76",
  124. },
  125. },
  126. },
  127. },
  128. want: "vol-0fc54c5e83b8d2b76",
  129. },
  130. {
  131. name: "aws ebs with bare volume id is left unchanged",
  132. pv: &PersistentVolume{
  133. Name: "pv-aws",
  134. Spec: v1.PersistentVolumeSpec{
  135. PersistentVolumeSource: v1.PersistentVolumeSource{
  136. AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{
  137. VolumeID: "vol-abc123",
  138. },
  139. },
  140. },
  141. },
  142. want: "vol-abc123",
  143. },
  144. {
  145. name: "aws ebs with empty volume id yields empty string",
  146. pv: &PersistentVolume{
  147. Name: "pv-aws",
  148. Spec: v1.PersistentVolumeSpec{
  149. PersistentVolumeSource: v1.PersistentVolumeSource{
  150. AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{VolumeID: ""},
  151. },
  152. },
  153. },
  154. want: "",
  155. },
  156. {
  157. name: "csi uses volume handle",
  158. pv: &PersistentVolume{
  159. Name: "pv-csi",
  160. Spec: v1.PersistentVolumeSpec{
  161. PersistentVolumeSource: v1.PersistentVolumeSource{
  162. CSI: &v1.CSIPersistentVolumeSource{VolumeHandle: "vol-csi-1"},
  163. },
  164. },
  165. },
  166. want: "vol-csi-1",
  167. },
  168. {
  169. // Documents current behavior: a CSI source with an empty handle
  170. // returns "" rather than falling back to pv.Name.
  171. name: "csi with empty volume handle returns empty string",
  172. pv: &PersistentVolume{
  173. Name: "pv-csi",
  174. Spec: v1.PersistentVolumeSpec{
  175. PersistentVolumeSource: v1.PersistentVolumeSource{
  176. CSI: &v1.CSIPersistentVolumeSource{VolumeHandle: ""},
  177. },
  178. },
  179. },
  180. want: "",
  181. },
  182. {
  183. name: "no recognized source falls back to pv name",
  184. pv: &PersistentVolume{
  185. Name: "pv-nfs",
  186. Spec: v1.PersistentVolumeSpec{},
  187. },
  188. want: "pv-nfs",
  189. },
  190. {
  191. // GCE branch is checked before CSI, so GCE wins when both are set.
  192. name: "gce takes precedence over csi",
  193. pv: &PersistentVolume{
  194. Name: "pv-both",
  195. Spec: v1.PersistentVolumeSpec{
  196. PersistentVolumeSource: v1.PersistentVolumeSource{
  197. GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{PDName: "gce-wins"},
  198. CSI: &v1.CSIPersistentVolumeSource{VolumeHandle: "csi-loses"},
  199. },
  200. },
  201. },
  202. want: "gce-wins",
  203. },
  204. }
  205. for _, tt := range tests {
  206. t.Run(tt.name, func(t *testing.T) {
  207. if got := GetPVProviderID(tt.pv); got != tt.want {
  208. t.Errorf("getPVProviderID() = %q, want %q", got, tt.want)
  209. }
  210. })
  211. }
  212. }
  213. func Test_persistentVolumeAWSRegex(t *testing.T) {
  214. tests := []struct {
  215. name string
  216. input string
  217. want string // expected capture group 1, or "" for no match
  218. }{
  219. {
  220. name: "standard aws:// volume id",
  221. input: "aws://us-east-2a/vol-0fc54c5e83b8d2b76",
  222. want: "vol-0fc54c5e83b8d2b76",
  223. },
  224. {
  225. name: "trailing path segment stops at slash",
  226. input: "aws://us-east-2a/vol-123/extra",
  227. want: "vol-123",
  228. },
  229. {
  230. name: "bare volume id does not match",
  231. input: "vol-abc123",
  232. want: "",
  233. },
  234. {
  235. name: "too few segments does not match",
  236. input: "aws://vol-123",
  237. want: "",
  238. },
  239. {
  240. name: "empty string does not match",
  241. input: "",
  242. want: "",
  243. },
  244. }
  245. for _, tt := range tests {
  246. t.Run(tt.name, func(t *testing.T) {
  247. match := persistentVolumeAWSRegex.FindStringSubmatch(tt.input)
  248. got := ""
  249. if len(match) >= 2 {
  250. got = match[1]
  251. }
  252. if got != tt.want {
  253. t.Errorf("persistentVolumeAWSRegex on %q = %q, want %q", tt.input, got, tt.want)
  254. }
  255. })
  256. }
  257. }