mirror of https://github.com/portainer/portainer
				
				
				
			fix(db): fix marshalling code so that we're compatible with the existing db (#6286)
* special handling for non-json types * added tests for json MarshalObject * another attempt * Fix marshal/unmarshal code for VERSION bucket * use short form * don't discard err * fix the json_test.go * remove duplicate string * added uuid tests * updated case for strings Co-authored-by: zees-dev <dev.786zshan@gmail.com>pull/6295/head
							parent
							
								
									187b66f5cb
								
							
						
					
					
						commit
						33a29159d2
					
				| 
						 | 
				
			
			@ -8,12 +8,29 @@ import (
 | 
			
		|||
 | 
			
		||||
// MarshalObject encodes an object to binary format
 | 
			
		||||
func MarshalObject(object interface{}) ([]byte, error) {
 | 
			
		||||
	// Special case for the VERSION bucket. Here we're not using json
 | 
			
		||||
	if v, ok := object.(string); ok {
 | 
			
		||||
		return []byte(v), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return json.Marshal(object)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalObject decodes an object from binary data
 | 
			
		||||
func UnmarshalObject(data []byte, object interface{}) error {
 | 
			
		||||
	return json.Unmarshal(data, object)
 | 
			
		||||
	// Special case for the VERSION bucket. Here we're not using json
 | 
			
		||||
	// So we need to return it as a string
 | 
			
		||||
	err := json.Unmarshal(data, object)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if s, ok := object.(*string); ok {
 | 
			
		||||
			*s = string(data)
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalObjectWithJsoniter decodes an object from binary data
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,122 @@
 | 
			
		|||
package boltdb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/gofrs/uuid"
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const jsonobject = `{"LogoURL":"","BlackListedLabels":[],"AuthenticationMethod":1,"LDAPSettings":{"AnonymousMode":true,"ReaderDN":"","URL":"","TLSConfig":{"TLS":false,"TLSSkipVerify":false},"StartTLS":false,"SearchSettings":[{"BaseDN":"","Filter":"","UserNameAttribute":""}],"GroupSearchSettings":[{"GroupBaseDN":"","GroupFilter":"","GroupAttribute":""}],"AutoCreateUsers":true},"OAuthSettings":{"ClientID":"","AccessTokenURI":"","AuthorizationURI":"","ResourceURI":"","RedirectURI":"","UserIdentifier":"","Scopes":"","OAuthAutoCreateUsers":false,"DefaultTeamID":0,"SSO":true,"LogoutURI":"","KubeSecretKey":"j0zLVtY/lAWBk62ByyF0uP80SOXaitsABP0TTJX8MhI="},"OpenAMTConfiguration":{"Enabled":false,"MPSServer":"","Credentials":{"MPSUser":"","MPSPassword":"","MPSToken":""},"DomainConfiguration":{"CertFileText":"","CertPassword":"","DomainName":""},"WirelessConfiguration":null},"FeatureFlagSettings":{},"SnapshotInterval":"5m","TemplatesURL":"https://raw.githubusercontent.com/portainer/templates/master/templates-2.0.json","EdgeAgentCheckinInterval":5,"EnableEdgeComputeFeatures":false,"UserSessionTimeout":"8h","KubeconfigExpiry":"0","EnableTelemetry":true,"HelmRepositoryURL":"https://charts.bitnami.com/bitnami","KubectlShellImage":"portainer/kubectl-shell","DisplayDonationHeader":false,"DisplayExternalContributors":false,"EnableHostManagementFeatures":false,"AllowVolumeBrowserForRegularUsers":false,"AllowBindMountsForRegularUsers":false,"AllowPrivilegedModeForRegularUsers":false,"AllowHostNamespaceForRegularUsers":false,"AllowStackManagementForRegularUsers":false,"AllowDeviceMappingForRegularUsers":false,"AllowContainerCapabilitiesForRegularUsers":false}`
 | 
			
		||||
 | 
			
		||||
func Test_MarshalObject(t *testing.T) {
 | 
			
		||||
	is := assert.New(t)
 | 
			
		||||
 | 
			
		||||
	uuid := uuid.Must(uuid.NewV4())
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		object   interface{}
 | 
			
		||||
		expected string
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			object:   nil,
 | 
			
		||||
			expected: `null`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			object:   true,
 | 
			
		||||
			expected: `true`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			object:   false,
 | 
			
		||||
			expected: `false`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			object:   123,
 | 
			
		||||
			expected: `123`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			object:   "456",
 | 
			
		||||
			expected: "456",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			object:   uuid,
 | 
			
		||||
			expected: "\"" + uuid.String() + "\"",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			object:   uuid.String(),
 | 
			
		||||
			expected: uuid.String(),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			object:   map[string]interface{}{"key": "value"},
 | 
			
		||||
			expected: `{"key":"value"}`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			object:   []bool{true, false},
 | 
			
		||||
			expected: `[true,false]`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			object:   []int{1, 2, 3},
 | 
			
		||||
			expected: `[1,2,3]`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			object:   []string{"1", "2", "3"},
 | 
			
		||||
			expected: `["1","2","3"]`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			object:   []map[string]interface{}{{"key1": "value1"}, {"key2": "value2"}},
 | 
			
		||||
			expected: `[{"key1":"value1"},{"key2":"value2"}]`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			object:   []interface{}{1, "2", false, map[string]interface{}{"key1": "value1"}},
 | 
			
		||||
			expected: `[1,"2",false,{"key1":"value1"}]`,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, test := range tests {
 | 
			
		||||
		t.Run(fmt.Sprintf("%s -> %s", test.object, test.expected), func(t *testing.T) {
 | 
			
		||||
			data, err := MarshalObject(test.object)
 | 
			
		||||
			is.NoError(err)
 | 
			
		||||
			is.Equal(test.expected, string(data))
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Test_UnMarshalObject(t *testing.T) {
 | 
			
		||||
	is := assert.New(t)
 | 
			
		||||
 | 
			
		||||
	// Based on actual data entering and what we expect out of the function
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		object   []byte
 | 
			
		||||
		expected string
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			object:   []byte(""),
 | 
			
		||||
			expected: "",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			object:   []byte("35"),
 | 
			
		||||
			expected: "35",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			// An unmarshalled byte string should return the same without error
 | 
			
		||||
			object:   []byte("9ca4a1dd-a439-4593-b386-a7dfdc2e9fc6"),
 | 
			
		||||
			expected: "9ca4a1dd-a439-4593-b386-a7dfdc2e9fc6",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			// An unmarshalled json object string should return the same as a string without error also
 | 
			
		||||
			object:   []byte(jsonobject),
 | 
			
		||||
			expected: jsonobject,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, test := range tests {
 | 
			
		||||
		t.Run(fmt.Sprintf("%s -> %s", test.object, test.expected), func(t *testing.T) {
 | 
			
		||||
			var object string
 | 
			
		||||
			err := UnmarshalObject(test.object, &object)
 | 
			
		||||
			is.NoError(err)
 | 
			
		||||
			is.Equal(test.expected, string(object))
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue