sigs.k8s.io/external-dns@v0.14.1/provider/pihole/pihole_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package pihole 18 19 import ( 20 "context" 21 "reflect" 22 "testing" 23 24 "sigs.k8s.io/external-dns/endpoint" 25 "sigs.k8s.io/external-dns/plan" 26 ) 27 28 type testPiholeClient struct { 29 endpoints []*endpoint.Endpoint 30 requests *requestTracker 31 } 32 33 func (t *testPiholeClient) listRecords(ctx context.Context, rtype string) ([]*endpoint.Endpoint, error) { 34 out := make([]*endpoint.Endpoint, 0) 35 for _, ep := range t.endpoints { 36 if ep.RecordType == rtype { 37 out = append(out, ep) 38 } 39 } 40 return out, nil 41 } 42 43 func (t *testPiholeClient) createRecord(ctx context.Context, ep *endpoint.Endpoint) error { 44 t.endpoints = append(t.endpoints, ep) 45 t.requests.createRequests = append(t.requests.createRequests, ep) 46 return nil 47 } 48 49 func (t *testPiholeClient) deleteRecord(ctx context.Context, ep *endpoint.Endpoint) error { 50 newEPs := make([]*endpoint.Endpoint, 0) 51 for _, existing := range t.endpoints { 52 if existing.DNSName != ep.DNSName && existing.Targets[0] != ep.Targets[0] { 53 newEPs = append(newEPs, existing) 54 } 55 } 56 t.endpoints = newEPs 57 t.requests.deleteRequests = append(t.requests.deleteRequests, ep) 58 return nil 59 } 60 61 type requestTracker struct { 62 createRequests []*endpoint.Endpoint 63 deleteRequests []*endpoint.Endpoint 64 } 65 66 func (r *requestTracker) clear() { 67 r.createRequests = nil 68 r.deleteRequests = nil 69 } 70 71 func TestNewPiholeProvider(t *testing.T) { 72 // Test invalid configuration 73 _, err := NewPiholeProvider(PiholeConfig{}) 74 if err == nil { 75 t.Error("Expected error from invalid configuration") 76 } 77 // Test valid configuration 78 _, err = NewPiholeProvider(PiholeConfig{Server: "test.example.com"}) 79 if err != nil { 80 t.Error("Expected no error from valid configuration, got:", err) 81 } 82 } 83 84 func TestProvider(t *testing.T) { 85 requests := requestTracker{} 86 p := &PiholeProvider{ 87 api: &testPiholeClient{endpoints: make([]*endpoint.Endpoint, 0), requests: &requests}, 88 } 89 90 records, err := p.Records(context.Background()) 91 if err != nil { 92 t.Fatal(err) 93 } 94 if len(records) != 0 { 95 t.Fatal("Expected empty list of records, got:", records) 96 } 97 98 // Populate the provider with records 99 records = []*endpoint.Endpoint{ 100 { 101 DNSName: "test1.example.com", 102 Targets: []string{"192.168.1.1"}, 103 RecordType: endpoint.RecordTypeA, 104 }, 105 { 106 DNSName: "test2.example.com", 107 Targets: []string{"192.168.1.2"}, 108 RecordType: endpoint.RecordTypeA, 109 }, 110 { 111 DNSName: "test3.example.com", 112 Targets: []string{"192.168.1.3"}, 113 RecordType: endpoint.RecordTypeA, 114 }, 115 } 116 if err := p.ApplyChanges(context.Background(), &plan.Changes{ 117 Create: records, 118 }); err != nil { 119 t.Fatal(err) 120 } 121 122 // Test records are correct on retrieval 123 124 newRecords, err := p.Records(context.Background()) 125 if err != nil { 126 t.Fatal(err) 127 } 128 if len(newRecords) != 3 { 129 t.Fatal("Expected list of 3 records, got:", records) 130 } 131 if len(requests.createRequests) != 3 { 132 t.Fatal("Expected 3 create requests, got:", requests.createRequests) 133 } 134 if len(requests.deleteRequests) != 0 { 135 t.Fatal("Expected no delete requests, got:", requests.deleteRequests) 136 } 137 138 for idx, record := range records { 139 if newRecords[idx].DNSName != record.DNSName { 140 t.Error("DNS Name malformed on retrieval, got:", newRecords[idx].DNSName, "expected:", record.DNSName) 141 } 142 if newRecords[idx].Targets[0] != record.Targets[0] { 143 t.Error("Targets malformed on retrieval, got:", newRecords[idx].Targets, "expected:", record.Targets) 144 } 145 146 if !reflect.DeepEqual(requests.createRequests[idx], record) { 147 t.Error("Unexpected create request, got:", newRecords[idx].DNSName, "expected:", record.DNSName) 148 } 149 } 150 151 requests.clear() 152 153 // Test delete a record 154 155 records = []*endpoint.Endpoint{ 156 { 157 DNSName: "test1.example.com", 158 Targets: []string{"192.168.1.1"}, 159 RecordType: endpoint.RecordTypeA, 160 }, 161 { 162 DNSName: "test2.example.com", 163 Targets: []string{"192.168.1.2"}, 164 RecordType: endpoint.RecordTypeA, 165 }, 166 } 167 recordToDelete := endpoint.Endpoint{ 168 DNSName: "test3.example.com", 169 Targets: []string{"192.168.1.3"}, 170 RecordType: endpoint.RecordTypeA, 171 } 172 if err := p.ApplyChanges(context.Background(), &plan.Changes{ 173 Delete: []*endpoint.Endpoint{ 174 &recordToDelete, 175 }, 176 }); err != nil { 177 t.Fatal(err) 178 } 179 180 // Test records are updated 181 newRecords, err = p.Records(context.Background()) 182 if err != nil { 183 t.Fatal(err) 184 } 185 if len(newRecords) != 2 { 186 t.Fatal("Expected list of 2 records, got:", records) 187 } 188 if len(requests.createRequests) != 0 { 189 t.Fatal("Expected no create requests, got:", requests.createRequests) 190 } 191 if len(requests.deleteRequests) != 1 { 192 t.Fatal("Expected 1 delete request, got:", requests.deleteRequests) 193 } 194 195 for idx, record := range records { 196 if newRecords[idx].DNSName != record.DNSName { 197 t.Error("DNS Name malformed on retrieval, got:", newRecords[idx].DNSName, "expected:", record.DNSName) 198 } 199 if newRecords[idx].Targets[0] != record.Targets[0] { 200 t.Error("Targets malformed on retrieval, got:", newRecords[idx].Targets, "expected:", record.Targets) 201 } 202 } 203 204 if !reflect.DeepEqual(requests.deleteRequests[0], &recordToDelete) { 205 t.Error("Unexpected delete request, got:", requests.deleteRequests[0], "expected:", recordToDelete) 206 } 207 208 requests.clear() 209 210 // Test update a record 211 212 records = []*endpoint.Endpoint{ 213 { 214 DNSName: "test1.example.com", 215 Targets: []string{"192.168.1.1"}, 216 RecordType: endpoint.RecordTypeA, 217 }, 218 { 219 DNSName: "test2.example.com", 220 Targets: []string{"10.0.0.1"}, 221 RecordType: endpoint.RecordTypeA, 222 }, 223 } 224 if err := p.ApplyChanges(context.Background(), &plan.Changes{ 225 UpdateOld: []*endpoint.Endpoint{ 226 { 227 DNSName: "test1.example.com", 228 Targets: []string{"192.168.1.1"}, 229 RecordType: endpoint.RecordTypeA, 230 }, 231 { 232 DNSName: "test2.example.com", 233 Targets: []string{"192.168.1.2"}, 234 RecordType: endpoint.RecordTypeA, 235 }, 236 }, 237 UpdateNew: []*endpoint.Endpoint{ 238 { 239 DNSName: "test1.example.com", 240 Targets: []string{"192.168.1.1"}, 241 RecordType: endpoint.RecordTypeA, 242 }, 243 { 244 DNSName: "test2.example.com", 245 Targets: []string{"10.0.0.1"}, 246 RecordType: endpoint.RecordTypeA, 247 }, 248 }, 249 }); err != nil { 250 t.Fatal(err) 251 } 252 253 // Test records are updated 254 newRecords, err = p.Records(context.Background()) 255 if err != nil { 256 t.Fatal(err) 257 } 258 if len(newRecords) != 2 { 259 t.Fatal("Expected list of 2 records, got:", records) 260 } 261 if len(requests.createRequests) != 1 { 262 t.Fatal("Expected 1 create request, got:", requests.createRequests) 263 } 264 if len(requests.deleteRequests) != 1 { 265 t.Fatal("Expected 1 delete request, got:", requests.deleteRequests) 266 } 267 268 for idx, record := range records { 269 if newRecords[idx].DNSName != record.DNSName { 270 t.Error("DNS Name malformed on retrieval, got:", newRecords[idx].DNSName, "expected:", record.DNSName) 271 } 272 if newRecords[idx].Targets[0] != record.Targets[0] { 273 t.Error("Targets malformed on retrieval, got:", newRecords[idx].Targets, "expected:", record.Targets) 274 } 275 } 276 277 expectedCreate := endpoint.Endpoint{ 278 DNSName: "test2.example.com", 279 Targets: []string{"10.0.0.1"}, 280 RecordType: endpoint.RecordTypeA, 281 } 282 expectedDelete := endpoint.Endpoint{ 283 DNSName: "test2.example.com", 284 Targets: []string{"192.168.1.2"}, 285 RecordType: endpoint.RecordTypeA, 286 } 287 288 if !reflect.DeepEqual(requests.createRequests[0], &expectedCreate) { 289 t.Error("Unexpected create request, got:", requests.createRequests[0], "expected:", &expectedCreate) 290 } 291 if !reflect.DeepEqual(requests.deleteRequests[0], &expectedDelete) { 292 t.Error("Unexpected delete request, got:", requests.deleteRequests[0], "expected:", &expectedDelete) 293 } 294 295 requests.clear() 296 }