Skip to content

Commit

Permalink
fix: xml configurations may not be in the same propretry order after …
Browse files Browse the repository at this point in the history
…marshal (zncdatadev#82)
  • Loading branch information
whg517 authored Jul 22, 2024
1 parent 7281608 commit 03974ee
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 10 deletions.
22 changes: 20 additions & 2 deletions pkg/util/xml.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package util
import (
"encoding/xml"
"slices"
"sort"
"strings"
)

Expand Down Expand Up @@ -36,6 +37,9 @@ func NewXMLConfiguration() *XMLConfiguration {

func NewXMLConfigurationFromString(xmlData string) (*XMLConfiguration, error) {
config := &XMLConfiguration{}

xmlData = strings.TrimLeft(xmlData, " \t\n\r")

headerEnd := strings.Index(xmlData, "<configuration>")
if headerEnd != -1 {
config.Header = xmlData[:headerEnd]
Expand All @@ -62,7 +66,7 @@ func (x *XMLConfiguration) GetProperty(name string) (Property, bool) {
return Property{}, false
}

func (x *XMLConfiguration) AddProperty(p Property) {
func (x *XMLConfiguration) addProperty(p Property) {
for i, existingProperty := range x.Configuration.Properties {
if existingProperty.Name == p.Name {
x.Configuration.Properties[i] = p // update
Expand All @@ -72,14 +76,27 @@ func (x *XMLConfiguration) AddProperty(p Property) {
x.Configuration.Properties = append(x.Configuration.Properties, p) // add
}

func (x *XMLConfiguration) sort() {
sort.Slice(x.Configuration.Properties, func(i, j int) bool {
return x.Configuration.Properties[i].Name < x.Configuration.Properties[j].Name
})
}

func (x *XMLConfiguration) AddProperty(p Property) {
x.addProperty(p)
x.sort()
}

func (x *XMLConfiguration) AddPropertyWithString(name, value, description string) {
x.AddProperty(Property{Name: name, Value: value, Description: description})
}

func (x *XMLConfiguration) AddPropertiesWithMap(properties map[string]string) {
for name, value := range properties {
x.AddProperty(Property{Name: name, Value: value})
x.addProperty(Property{Name: name, Value: value})
}

x.sort()
}

func (x *XMLConfiguration) DeleteProperties(names ...string) {
Expand All @@ -102,6 +119,7 @@ func (x *XMLConfiguration) getHeader() string {
}

func (x *XMLConfiguration) Marshal() (string, error) {
x.sort()
data, err := xml.MarshalIndent(x.Configuration, "", " ")
if err != nil {
return "", err
Expand Down
60 changes: 52 additions & 8 deletions pkg/util/xml_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package util

import "testing"
import (
"testing"
)

func TestXMLConfiguration(t *testing.T) {
xmlData := `
Expand Down Expand Up @@ -43,8 +45,7 @@ func TestXMLConfiguration(t *testing.T) {
</configuration>
`

expectedXMLData := `
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
expectedXMLData := `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?><!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
Expand All @@ -62,6 +63,11 @@ func TestXMLConfiguration(t *testing.T) {
limitations under the License.
-->
<configuration>
<property>
<name>hive.metastore.db.type</name>
<value>DERBY</value>
<description>Expects one of [derby, oracle, mysql, mssql, postgres]. Type of database used by the metastore. Information schema &amp; JDBCStorageHandler depend on it.</description>
</property>
<property>
<name>hive.metastore.warehouse.dir</name>
<value>/user/hive/warehouse</value>
Expand All @@ -76,11 +82,6 @@ func TestXMLConfiguration(t *testing.T) {
For example, jdbc:postgresql://myhost/db?ssl=true for postgres database.
</description>
</property>
<property>
<name>hive.metastore.db.type</name>
<value>DERBY</value>
<description>Expects one of [derby, oracle, mysql, mssql, postgres]. Type of database used by the metastore. Information schema &amp; JDBCStorageHandler depend on it.</description>
</property>
</configuration>
`

Expand Down Expand Up @@ -269,6 +270,14 @@ func TestXMLConfiguration_AddProperty(t *testing.T) {
if p.Value != "value1" {
t.Errorf("Property 'property1' has incorrect value. Expected: value1, Got: %s", p.Value)
}

property.Value = "value2"
config.AddProperty(property)

p, ok = config.GetProperty("property1")
if !ok {
t.Errorf("Expected property 'property1' not found")
}
}

func TestXMLConfiguration_DeleteProperties(t *testing.T) {
Expand Down Expand Up @@ -323,3 +332,38 @@ func TestXMLConfiguration_Marshal(t *testing.T) {
t.Errorf("Marshalled XML does not match expected XML. Expected:\n%s\nGot:\n%s", expectedXML, xmlData)
}
}

func TestXMLConfiguration_Marshal_NoHeader(t *testing.T) {
xmlData := `
<configuration>
<property>
<name>property1</name>
<value>value1</value>
</property>
</configuration>
`

expectedXML := `<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>property1</name>
<value>value1</value>
</property>
</configuration>
`

config, err := NewXMLConfigurationFromString(xmlData)
if err != nil {
t.Errorf("Failed to create XML configuration from string: %v", err)
}

xmlData, err = config.Marshal()
if err != nil {
t.Errorf("Failed to marshal XML configuration: %v", err)
}

if xmlData != expectedXML {
t.Errorf("Marshalled XML does not match expected XML. Expected:\n%s\nGot:\n%s", expectedXML, xmlData)
}
}

0 comments on commit 03974ee

Please sign in to comment.