gopkg.in/libvirt/libvirt-go-xml.v5@v5.10.0/xml_test.go (about) 1 // +build xmlroundtrip 2 3 /* 4 * This file is part of the libvirt-go-xml project 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 * 24 * Copyright (C) 2016 Red Hat, Inc. 25 * 26 */ 27 28 package libvirtxml 29 30 import ( 31 "fmt" 32 "io/ioutil" 33 "os" 34 "os/exec" 35 "strings" 36 "testing" 37 ) 38 39 var xmldirs = []string{ 40 "testdata/libvirt/tests/bhyveargv2xmldata", 41 "testdata/libvirt/tests/bhyvexml2argvdata", 42 "testdata/libvirt/tests/bhyvexml2xmloutdata", 43 "testdata/libvirt/tests/capabilityschemadata", 44 "testdata/libvirt/tests/cputestdata", 45 "testdata/libvirt/tests/domaincapsdata", 46 "testdata/libvirt/tests/domainconfdata", 47 "testdata/libvirt/tests/domainschemadata", 48 "testdata/libvirt/tests/genericxml2xmlindata", 49 "testdata/libvirt/tests/genericxml2xmloutdata", 50 "testdata/libvirt/tests/interfaceschemadata", 51 "testdata/libvirt/tests/libxlxml2domconfigdata", 52 "testdata/libvirt/tests/lxcconf2xmldata", 53 "testdata/libvirt/tests/lxcxml2xmldata", 54 "testdata/libvirt/tests/lxcxml2xmloutdata", 55 "testdata/libvirt/tests/networkxml2confdata", 56 "testdata/libvirt/tests/networkxml2firewalldata", 57 "testdata/libvirt/tests/networkxml2xmlin", 58 "testdata/libvirt/tests/networkxml2xmlout", 59 "testdata/libvirt/tests/networkxml2xmlupdatein", 60 "testdata/libvirt/tests/networkxml2xmlupdateout", 61 "testdata/libvirt/tests/nodedevschemadata", 62 "testdata/libvirt/tests/nwfilterxml2firewalldata", 63 "testdata/libvirt/tests/nwfilterxml2xmlin", 64 "testdata/libvirt/tests/nwfilterxml2xmlout", 65 "testdata/libvirt/tests/qemuagentdata", 66 "testdata/libvirt/tests/qemucapabilitiesdata", 67 "testdata/libvirt/tests/qemudomainsnapshotxml2xmlin", 68 "testdata/libvirt/tests/qemudomainsnapshotxml2xmlout", 69 "testdata/libvirt/tests/qemuhotplugtestcpus", 70 "testdata/libvirt/tests/qemuhotplugtestdevices", 71 "testdata/libvirt/tests/qemuhotplugtestdomains", 72 "testdata/libvirt/tests/qemumemlockdata", 73 "testdata/libvirt/tests/qemuxml2argvdata", 74 "testdata/libvirt/tests/qemuxml2xmloutdata", 75 "testdata/libvirt/tests/secretxml2xmlin", 76 "testdata/libvirt/tests/securityselinuxlabeldata", 77 "testdata/libvirt/tests/storagepoolschemadata", 78 "testdata/libvirt/tests/storagepoolxml2xmlin", 79 "testdata/libvirt/tests/storagepoolxml2xmlout", 80 "testdata/libvirt/tests/storagevolschemadata", 81 "testdata/libvirt/tests/storagevolxml2xmlin", 82 "testdata/libvirt/tests/storagevolxml2xmlout", 83 "testdata/libvirt/tests/vircaps2xmldata", 84 "testdata/libvirt/tests/virnwfilterbindingxml2xmldata", 85 "testdata/libvirt/tests/virnetworkportxml2xmldata", 86 "testdata/libvirt/tests/virnwfilterbindingxml2xmldata", 87 "testdata/libvirt/tests/virstorageutildata", 88 "testdata/libvirt/tests/vmx2xmldata", 89 "testdata/libvirt/tests/xlconfigdata", 90 "testdata/libvirt/tests/xmconfigdata", 91 "testdata/libvirt/tests/xml2vmxdata", 92 } 93 94 var consoletype = "/domain[0]/devices[0]/console[0]/@type" 95 var volsrc = "/volume[0]/source[0]" 96 97 var blacklist = map[string]bool{ 98 // intentionally invalid xml 99 "testdata/libvirt/tests/genericxml2xmlindata/chardev-unix-redirdev-missing-path.xml": true, 100 "testdata/libvirt/tests/genericxml2xmlindata/chardev-unix-rng-missing-path.xml": true, 101 "testdata/libvirt/tests/qemuxml2argvdata/virtio-rng-egd-crash.xml": true, 102 "testdata/libvirt/tests/genericxml2xmlindata/chardev-unix-smartcard-missing-path.xml": true, 103 "testdata/libvirt/tests/genericxml2xmlindata/chardev-tcp-multiple-source.xml": true, 104 "testdata/libvirt/tests/networkxml2xmlupdatein/dns-host-gateway-incomplete.xml": true, 105 "testdata/libvirt/tests/networkxml2xmlupdatein/host-new-incomplete.xml": true, 106 "testdata/libvirt/tests/networkxml2xmlupdatein/unparsable-dns-host.xml": true, 107 // udp source in different order 108 "testdata/libvirt/tests/genericxml2xmlindata/chardev-udp.xml": true, 109 "testdata/libvirt/tests/genericxml2xmlindata/chardev-udp-multiple-source.xml": true, 110 } 111 112 var extraActualNodes = map[string][]string{ 113 114 "testdata/libvirt/tests/qemuxml2argvdata/disk-discard.xml": []string{ 115 "/domain[0]/devices[0]/disk[0]/@type", 116 }, 117 "testdata/libvirt/tests/qemuxml2argvdata/fs9p-ccw.xml": []string{ 118 "/domain[0]/devices[0]/filesystem[1]/@type", 119 "/domain[0]/devices[0]/filesystem[2]/@type", 120 }, 121 "testdata/libvirt/tests/qemuxml2argvdata/fs9p.xml": []string{ 122 "/domain[0]/devices[0]/filesystem[1]/@type", 123 "/domain[0]/devices[0]/filesystem[2]/@type", 124 }, 125 "testdata/libvirt/tests/qemuxml2argvdata/disk-drive-discard.xml": []string{ 126 "/domain[0]/devices[0]/disk[0]/@type", 127 }, 128 "testdata/libvirt/tests/genericxml2xmlindata/chardev-udp.xml": []string{ 129 "/domain[0]/devices[0]/channel[0]/source[0]/@mode", 130 }, 131 "testdata/libvirt/tests/qemuxml2argvdata/disk-mirror-old.xml": []string{ 132 "/domain[0]/devices[0]/disk[0]/mirror[0]/@type", 133 "/domain[0]/devices[0]/disk[0]/mirror[0]/source[0]", 134 "/domain[0]/devices[0]/disk[2]/mirror[0]/@type", 135 "/domain[0]/devices[0]/disk[2]/mirror[0]/format[0]", 136 "/domain[0]/devices[0]/disk[2]/mirror[0]/source[0]", 137 }, 138 "testdata/libvirt/tests/xlconfigdata/test-fullvirt-ovswitch-tagged.xml": []string{ 139 "/domain[0]/devices[0]/interface[0]/virtualport[0]/parameters[0]", 140 }, 141 "testdata/libvirt/tests/xlconfigdata/test-fullvirt-ovswitch-trunked.xml": []string{ 142 "/domain[0]/devices[0]/interface[0]/virtualport[0]/parameters[0]", 143 }, 144 145 "testdata/libvirt/tests/networkxml2xmlin/openvswitch-net.xml": []string{ 146 "/network[0]/virtualport[0]/parameters[0]", 147 }, 148 "testdata/libvirt/tests/networkxml2xmlout/openvswitch-net.xml": []string{ 149 "/network[0]/virtualport[0]/parameters[0]", 150 }, 151 "testdata/libvirt/tests/networkxml2xmlupdateout/openvswitch-net-modified.xml": []string{ 152 "/network[0]/virtualport[0]/parameters[0]", 153 }, 154 "testdata/libvirt/tests/networkxml2xmlupdateout/openvswitch-net-more-portgroups.xml": []string{ 155 "/network[0]/virtualport[0]/parameters[0]", 156 }, 157 "testdata/libvirt/tests/networkxml2xmlupdateout/openvswitch-net-without-alice.xml": []string{ 158 "/network[0]/virtualport[0]/parameters[0]", 159 }, 160 "testdata/libvirt/tests/interfaceschemadata/bridge-vlan.xml": []string{ 161 "/interface[0]/bridge[0]/interface[0]/vlan[0]/interface[0]/@type", 162 }, 163 "testdata/libvirt/tests/interfaceschemadata/vlan.xml": []string{ 164 "/interface[0]/vlan[0]/interface[0]/@type", 165 }, 166 "testdata/libvirt/tests/qemudomainsnapshotxml2xmlin/disk_driver_name_null.xml": []string{ 167 "/domainsnapshot[0]/disks[0]/disk[0]/@type", 168 }, 169 "testdata/libvirt/tests/qemudomainsnapshotxml2xmlin/disk_snapshot.xml": []string{ 170 "/domainsnapshot[0]/disks[0]/disk[0]/@type", 171 "/domainsnapshot[0]/disks[0]/disk[1]/@type", 172 "/domainsnapshot[0]/disks[0]/disk[2]/@type", 173 "/domainsnapshot[0]/disks[0]/disk[3]/@type", 174 "/domainsnapshot[0]/disks[0]/disk[4]/@type", 175 }, 176 "testdata/libvirt/tests/qemudomainsnapshotxml2xmlout/disk_snapshot.xml": []string{ 177 "/domainsnapshot[0]/disks[0]/disk[0]/@type", 178 "/domainsnapshot[0]/disks[0]/disk[1]/@type", 179 "/domainsnapshot[0]/disks[0]/disk[2]/@type", 180 }, 181 "testdata/libvirt/tests/qemudomainsnapshotxml2xmlout/disk_snapshot_redefine.xml": []string{ 182 "/domainsnapshot[0]/disks[0]/disk[0]/@type", 183 "/domainsnapshot[0]/disks[0]/disk[1]/@type", 184 "/domainsnapshot[0]/disks[0]/disk[2]/@type", 185 }, 186 "testdata/libvirt/tests/qemudomainsnapshotxml2xmlout/external_vm_redefine.xml": []string{ 187 "/domainsnapshot[0]/disks[0]/disk[0]/@type", 188 }, 189 } 190 191 var extraExpectNodes = map[string][]string{ 192 "testdata/libvirt/tests/qemuxml2argvdata/usb-redir-filter.xml": []string{ 193 "/domain[0]/devices[0]/redirfilter[0]/usbdev[1]/@vendor", 194 "/domain[0]/devices[0]/redirfilter[0]/usbdev[1]/@product", 195 "/domain[0]/devices[0]/redirfilter[0]/usbdev[1]/@class", 196 "/domain[0]/devices[0]/redirfilter[0]/usbdev[1]/@version", 197 }, 198 "testdata/libvirt/tests/domainschemadata/domain-parallels-ct-simple.xml": []string{ 199 "/domain[0]/description[0]", 200 }, 201 "testdata/libvirt/tests/storagevolxml2xmlin/vol-encrypt1.xml": []string{volsrc}, 202 "testdata/libvirt/tests/storagevolxml2xmlin/vol-encrypt2.xml": []string{volsrc}, 203 "testdata/libvirt/tests/storagevolxml2xmlin/vol-file-backing.xml": []string{volsrc}, 204 "testdata/libvirt/tests/storagevolxml2xmlin/vol-file-iso.xml": []string{volsrc}, 205 "testdata/libvirt/tests/storagevolxml2xmlin/vol-file-naming.xml": []string{volsrc}, 206 "testdata/libvirt/tests/storagevolxml2xmlin/vol-file-qcow2.xml": []string{volsrc}, 207 "testdata/libvirt/tests/storagevolxml2xmlin/vol-file.xml": []string{volsrc}, 208 "testdata/libvirt/tests/storagevolxml2xmlin/vol-gluster-dir-neg-uid.xml": []string{volsrc}, 209 "testdata/libvirt/tests/storagevolxml2xmlin/vol-gluster-dir.xml": []string{volsrc}, 210 "testdata/libvirt/tests/storagevolxml2xmlin/vol-logical-backing.xml": []string{volsrc}, 211 "testdata/libvirt/tests/storagevolxml2xmlin/vol-logical.xml": []string{volsrc}, 212 "testdata/libvirt/tests/storagevolxml2xmlin/vol-luks-cipher.xml": []string{volsrc}, 213 "testdata/libvirt/tests/storagevolxml2xmlin/vol-luks-convert.xml": []string{volsrc}, 214 "testdata/libvirt/tests/storagevolxml2xmlin/vol-luks.xml": []string{volsrc}, 215 "testdata/libvirt/tests/storagevolxml2xmlin/vol-partition.xml": []string{volsrc}, 216 "testdata/libvirt/tests/storagevolxml2xmlin/vol-qcow2-0.10-lazy.xml": []string{volsrc}, 217 "testdata/libvirt/tests/storagevolxml2xmlin/vol-qcow2-1.1.xml": []string{volsrc}, 218 "testdata/libvirt/tests/storagevolxml2xmlin/vol-qcow2-lazy.xml": []string{volsrc}, 219 "testdata/libvirt/tests/storagevolxml2xmlin/vol-qcow2-encryption.xml": []string{volsrc}, 220 "testdata/libvirt/tests/storagevolxml2xmlin/vol-qcow2-nobacking.xml": []string{volsrc}, 221 "testdata/libvirt/tests/storagevolxml2xmlin/vol-qcow2-nocapacity-backing.xml": []string{volsrc}, 222 "testdata/libvirt/tests/storagevolxml2xmlin/vol-qcow2-nocapacity.xml": []string{volsrc}, 223 "testdata/libvirt/tests/storagevolxml2xmlin/vol-qcow2-nocow.xml": []string{volsrc}, 224 "testdata/libvirt/tests/storagevolxml2xmlin/vol-qcow2.xml": []string{volsrc}, 225 "testdata/libvirt/tests/storagevolxml2xmlin/vol-sheepdog.xml": []string{volsrc}, 226 "testdata/libvirt/tests/storagevolxml2xmlout/vol-file-backing.xml": []string{volsrc}, 227 "testdata/libvirt/tests/storagevolxml2xmlout/vol-file-iso.xml": []string{volsrc}, 228 "testdata/libvirt/tests/storagevolxml2xmlout/vol-file-naming.xml": []string{volsrc}, 229 "testdata/libvirt/tests/storagevolxml2xmlout/vol-file.xml": []string{volsrc}, 230 "testdata/libvirt/tests/storagevolxml2xmlout/vol-gluster-dir-neg-uid.xml": []string{volsrc}, 231 "testdata/libvirt/tests/storagevolxml2xmlout/vol-gluster-dir.xml": []string{volsrc}, 232 "testdata/libvirt/tests/storagevolxml2xmlout/vol-logical-backing.xml": []string{volsrc}, 233 "testdata/libvirt/tests/storagevolxml2xmlout/vol-logical.xml": []string{volsrc}, 234 "testdata/libvirt/tests/storagevolxml2xmlout/vol-luks-cipher.xml": []string{volsrc}, 235 "testdata/libvirt/tests/storagevolxml2xmlout/vol-luks.xml": []string{volsrc}, 236 "testdata/libvirt/tests/storagevolxml2xmlout/vol-partition.xml": []string{volsrc}, 237 "testdata/libvirt/tests/storagevolxml2xmlout/vol-qcow2-0.10-lazy.xml": []string{volsrc}, 238 "testdata/libvirt/tests/storagevolxml2xmlout/vol-qcow2-1.1.xml": []string{volsrc}, 239 "testdata/libvirt/tests/storagevolxml2xmlout/vol-qcow2-encryption.xml": []string{volsrc}, 240 "testdata/libvirt/tests/storagevolxml2xmlout/vol-qcow2-lazy.xml": []string{volsrc}, 241 "testdata/libvirt/tests/storagevolxml2xmlout/vol-qcow2-nobacking.xml": []string{volsrc}, 242 "testdata/libvirt/tests/storagevolxml2xmlout/vol-qcow2-nocapacity-backing.xml": []string{volsrc}, 243 "testdata/libvirt/tests/storagevolxml2xmlout/vol-qcow2-nocapacity.xml": []string{volsrc}, 244 "testdata/libvirt/tests/storagevolxml2xmlout/vol-qcow2-nocow.xml": []string{volsrc}, 245 "testdata/libvirt/tests/storagevolxml2xmlout/vol-qcow2.xml": []string{volsrc}, 246 "testdata/libvirt/tests/storagevolxml2xmlout/vol-sheepdog.xml": []string{volsrc}, 247 "testdata/libvirt/tests/qemudomainsnapshotxml2xmlin/disk_snapshot.xml": []string{ 248 "/domainsnapshot[0]/disks[0]/disk[3]/source[0]", 249 }, 250 } 251 252 func trimXML(xml string) string { 253 xml = strings.TrimSpace(xml) 254 if strings.HasPrefix(xml, "<?xml") { 255 end := strings.Index(xml, "?>") 256 if end != -1 { 257 xml = xml[end+2:] 258 xml = strings.TrimSpace(xml) 259 } 260 } 261 if strings.HasPrefix(xml, "<!--") { 262 end := strings.Index(xml, "-->") 263 if end != -1 { 264 xml = xml[end+3:] 265 xml = strings.TrimSpace(xml) 266 } 267 } 268 return xml 269 } 270 271 func testRoundTrip(t *testing.T, xml string, filename string) { 272 if strings.HasSuffix(filename, "-invalid.xml") { 273 return 274 } 275 276 xml = trimXML(xml) 277 278 var doc Document 279 if strings.HasPrefix(xml, "<domain ") { 280 doc = &Domain{} 281 } else if strings.HasPrefix(xml, "<capabilities") { 282 doc = &Caps{} 283 } else if strings.HasPrefix(xml, "<networkport") { 284 doc = &NetworkPort{} 285 } else if strings.HasPrefix(xml, "<network") { 286 doc = &Network{} 287 } else if strings.HasPrefix(xml, "<secret") { 288 doc = &Secret{} 289 } else if strings.HasPrefix(xml, "<device") { 290 doc = &NodeDevice{} 291 } else if strings.HasPrefix(xml, "<volume") { 292 doc = &StorageVolume{} 293 } else if strings.HasPrefix(xml, "<pool") { 294 doc = &StoragePool{} 295 } else if strings.HasPrefix(xml, "<cpuTest") || strings.HasPrefix(xml, "<cpudata") { 296 // Not a public schema 297 return 298 } else if strings.HasPrefix(xml, "<cpu") { 299 if strings.Contains(xml, "mode=") || strings.Contains(xml, "match=") { 300 doc = &DomainCPU{} 301 } else { 302 doc = &CapsHostCPU{} 303 } 304 } else if strings.HasPrefix(xml, "<filterbinding") { 305 doc = &NWFilterBinding{} 306 } else if strings.HasPrefix(xml, "<filter") { 307 doc = &NWFilter{} 308 } else if strings.HasPrefix(xml, "<interface") { 309 if strings.Contains(filename, "networkxml") { 310 doc = &NetworkForwardInterface{} 311 } else { 312 doc = &Interface{} 313 } 314 } else if strings.HasPrefix(xml, "<domainsnapshot") { 315 doc = &DomainSnapshot{} 316 } else if strings.HasPrefix(xml, "<domainCapabilities") { 317 doc = &DomainCaps{} 318 } else if strings.HasPrefix(xml, "<disk") { 319 doc = &DomainDisk{} 320 } else if strings.HasPrefix(xml, "<console") { 321 doc = &DomainConsole{} 322 } else if strings.HasPrefix(xml, "<channel") { 323 doc = &DomainChannel{} 324 } else if strings.HasPrefix(xml, "<watchdog") { 325 doc = &DomainWatchdog{} 326 } else if strings.HasPrefix(xml, "<shmem") { 327 doc = &DomainShmem{} 328 } else if strings.HasPrefix(xml, "<graphics") { 329 doc = &DomainGraphic{} 330 } else if strings.HasPrefix(xml, "<hostdev") { 331 doc = &DomainHostdev{} 332 } else if strings.HasPrefix(xml, "<host") { 333 if strings.Contains(xml, "mac=") { 334 doc = &NetworkDHCPHost{} 335 } else { 336 doc = &NetworkDNSHost{} 337 } 338 } else if strings.HasPrefix(xml, "<portgroup") { 339 doc = &NetworkPortGroup{} 340 } else if strings.HasPrefix(xml, "<txt") { 341 doc = &NetworkDNSTXT{} 342 } else if strings.HasPrefix(xml, "<srv") { 343 doc = &NetworkDNSSRV{} 344 } else if strings.HasPrefix(xml, "<range") { 345 doc = &NetworkDHCPRange{} 346 } else if strings.HasPrefix(xml, "<qemuCaps") || 347 strings.HasPrefix(xml, "<sources") || 348 strings.HasPrefix(xml, "<cpudata") || 349 strings.HasPrefix(xml, "<cliOutput") { 350 // Private libvirt internal XML schemas we don't 351 // need public API coverage for 352 return 353 } else { 354 t.Fatal(fmt.Errorf("Unexpected XML document schema in %s\n", filename)) 355 } 356 err := doc.Unmarshal(xml) 357 if err != nil { 358 t.Fatal(fmt.Errorf("Cannot parse file %s: %s\n", filename, err)) 359 } 360 361 newxml, err := doc.Marshal() 362 if err != nil { 363 t.Fatal(err) 364 } 365 366 extraExpectNodes, _ := extraExpectNodes[filename] 367 extraActualNodes, _ := extraActualNodes[filename] 368 err = testCompareXML(filename, xml, newxml, extraExpectNodes, extraActualNodes) 369 if err != nil { 370 if os.Getenv("LIBVIRT_DEBUG") == "1" { 371 fmt.Printf("Expected %s\n", xml) 372 fmt.Printf("Actual %s\n", newxml) 373 } 374 t.Fatal(err) 375 } 376 } 377 378 func syncGit(t *testing.T) { 379 _, err := os.Stat("testdata/libvirt/tests") 380 if err != nil { 381 if os.IsNotExist(err) { 382 msg, err := exec.Command("git", "clone", "--depth", "1", "https://libvirt.org/git/libvirt.git", "testdata/libvirt").CombinedOutput() 383 if err != nil { 384 t.Fatal(fmt.Errorf("Unable to clone libvirt.git: %s: %s", err, msg)) 385 } 386 } else { 387 t.Fatal(err) 388 } 389 } else { 390 here, err := os.Getwd() 391 if err != nil { 392 t.Fatal(err) 393 } 394 err = os.Chdir("testdata/libvirt") 395 if err != nil { 396 t.Fatal(err) 397 } 398 defer func() { 399 os.Chdir(here) 400 }() 401 msg, err := exec.Command("git", "pull").CombinedOutput() 402 if err != nil { 403 t.Fatal(fmt.Errorf("Unable to update libvirt.git: %s: %s", err, msg)) 404 } 405 } 406 } 407 408 func TestRoundTrip(t *testing.T) { 409 syncGit(t) 410 for _, xmldir := range xmldirs { 411 xmlfiles, err := ioutil.ReadDir(xmldir) 412 if err != nil { 413 t.Fatal(err) 414 } 415 416 for _, xmlfile := range xmlfiles { 417 if !xmlfile.IsDir() && strings.HasSuffix(xmlfile.Name(), ".xml") { 418 fname := xmldir + "/" + xmlfile.Name() 419 _, ok := blacklist[fname] 420 if ok { 421 continue 422 } 423 xml, err := ioutil.ReadFile(fname) 424 if err != nil { 425 t.Fatal(err) 426 } 427 testRoundTrip(t, string(xml), fname) 428 } 429 } 430 } 431 }