Skip to content

Commit 017f012

Browse files
thiagodasilvancw
authored andcommitted
Add symlink support
Added symlink support with tests. Symlink has been avaialable in Swift since version 2.17.0 and static links since 2.23.0 This checks /info to make sure symlink is supported before attempting to run symlink tests
1 parent 27a552e commit 017f012

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed

swift.go

+16
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,22 @@ func (c *Connection) ObjectCreate(container string, objectName string, checkHash
14851485
return
14861486
}
14871487

1488+
func (c *Connection) ObjectSymlinkCreate(container string, symlink string, targetAccount string, targetContainer string, targetObject string, targetEtag string) (headers Headers, err error) {
1489+
1490+
EMPTY_MD5 := "d41d8cd98f00b204e9800998ecf8427e"
1491+
symHeaders := Headers{}
1492+
contents := bytes.NewBufferString("")
1493+
if targetAccount != "" {
1494+
symHeaders["X-Symlink-Target-Account"] = targetAccount
1495+
}
1496+
if targetEtag != "" {
1497+
symHeaders["X-Symlink-Target-Etag"] = targetEtag
1498+
}
1499+
symHeaders["X-Symlink-Target"] = fmt.Sprintf("%s/%s", targetContainer, targetObject)
1500+
_, err = c.ObjectPut(container, symlink, contents, true, EMPTY_MD5, "application/symlink", symHeaders)
1501+
return
1502+
}
1503+
14881504
func (c *Connection) objectPut(container string, objectName string, contents io.Reader, checkHash bool, Hash string, contentType string, h Headers, parameters url.Values) (headers Headers, err error) {
14891505
extraHeaders := objectPutHeaders(objectName, &checkHash, Hash, contentType, h)
14901506
hash := md5.New()

swift_test.go

+125
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,14 @@ const (
5151
CURRENT_CONTAINER = "GoSwiftUnitTestCurrent"
5252
OBJECT = "test_object"
5353
OBJECT2 = "test_object2"
54+
SYMLINK_OBJECT = "test_symlink"
55+
SYMLINK_OBJECT2 = "test_symlink2"
5456
EMPTYOBJECT = "empty_test_object"
5557
CONTENTS = "12345"
5658
CONTENTS2 = "54321"
5759
CONTENT_SIZE = int64(len(CONTENTS))
5860
CONTENT_MD5 = "827ccb0eea8a706c4c34a16891f84e7b"
61+
CONTENT2_MD5 = "01cfcd4f6b8770febfb40cb906715822"
5962
EMPTY_MD5 = "d41d8cd98f00b204e9800998ecf8427e"
6063
SECRET_KEY = "b3968d0207b54ece87cccc06515a89d4"
6164
)
@@ -299,6 +302,12 @@ func isV3Api() bool {
299302
return strings.Contains(AuthUrl, "v3")
300303
}
301304

305+
func getSwinftInfo(t *testing.T) (info swift.SwiftInfo, err error) {
306+
c, rollback := makeConnectionAuth(t)
307+
defer rollback()
308+
return c.QueryInfo()
309+
}
310+
302311
func TestTransport(t *testing.T) {
303312
c, rollback := makeConnection(t)
304313
defer rollback()
@@ -908,6 +917,122 @@ func TestObjectEmpty(t *testing.T) {
908917
}
909918
}
910919

920+
func TestSymlinkObject(t *testing.T) {
921+
info, err := getSwinftInfo(t)
922+
if err != nil {
923+
t.Fatal(err)
924+
}
925+
if _, ok := info["symlink"]; !ok {
926+
// skip, symlink not supported
927+
t.Skip("skip, symlink not supported")
928+
return
929+
}
930+
c, rollback := makeConnectionWithContainer(t)
931+
defer rollback()
932+
933+
// write target objects
934+
err = c.ObjectPutBytes(CONTAINER, OBJECT, []byte(CONTENTS), "text/potato")
935+
if err != nil {
936+
t.Fatal(err)
937+
}
938+
defer func() {
939+
err = c.ObjectDelete(CONTAINER, OBJECT)
940+
if err != nil {
941+
t.Error(err)
942+
}
943+
}()
944+
945+
// test dynamic link
946+
_, err = c.ObjectSymlinkCreate(CONTAINER, SYMLINK_OBJECT, "", CONTAINER, OBJECT, "")
947+
if err != nil {
948+
t.Fatal(err)
949+
}
950+
defer func() {
951+
err = c.ObjectDelete(CONTAINER, SYMLINK_OBJECT)
952+
if err != nil {
953+
t.Error(err)
954+
}
955+
}()
956+
957+
md, _, err := c.Object(CONTAINER, SYMLINK_OBJECT)
958+
if err != nil {
959+
t.Error(err)
960+
}
961+
if md.ContentType != "text/potato" {
962+
t.Error("Bad content type", md.ContentType)
963+
}
964+
if md.Bytes != CONTENT_SIZE {
965+
t.Errorf("Bad length want 5 got %v", md.Bytes)
966+
}
967+
if md.Hash != CONTENT_MD5 {
968+
t.Errorf("Bad MD5 want %v got %v", CONTENT_MD5, md.Hash)
969+
}
970+
971+
}
972+
973+
func TestStaticSymlinkObject(t *testing.T) {
974+
info, err := getSwinftInfo(t)
975+
if err != nil {
976+
t.Fatal(err)
977+
}
978+
if sym, ok := info["symlink"].(map[string]interface{}); ok {
979+
if _, ok := sym["static_links"]; !ok {
980+
t.Skip("skip, static symlink not supported")
981+
return
982+
}
983+
} else {
984+
t.Skip("skip, symlink not supported")
985+
return
986+
}
987+
988+
c, rollback := makeConnectionWithContainer(t)
989+
defer rollback()
990+
991+
// write target objects
992+
err = c.ObjectPutBytes(CONTAINER, OBJECT2, []byte(CONTENTS2), "text/tomato")
993+
if err != nil {
994+
t.Fatal(err)
995+
}
996+
defer func() {
997+
err = c.ObjectDelete(CONTAINER, OBJECT2)
998+
if err != nil {
999+
t.Error(err)
1000+
}
1001+
}()
1002+
1003+
// test static link
1004+
// first with the wrong target etag
1005+
_, err = c.ObjectSymlinkCreate(CONTAINER, SYMLINK_OBJECT2, "", CONTAINER, OBJECT2, CONTENT_MD5)
1006+
if err == nil {
1007+
t.Error("Symlink with wrong target etag should have failed")
1008+
}
1009+
1010+
_, err = c.ObjectSymlinkCreate(CONTAINER, SYMLINK_OBJECT2, "", CONTAINER, OBJECT2, CONTENT2_MD5)
1011+
if err != nil {
1012+
t.Fatal(err)
1013+
}
1014+
defer func() {
1015+
err = c.ObjectDelete(CONTAINER, SYMLINK_OBJECT2)
1016+
if err != nil {
1017+
t.Error(err)
1018+
}
1019+
}()
1020+
1021+
md, _, err := c.Object(CONTAINER, SYMLINK_OBJECT2)
1022+
if err != nil {
1023+
t.Error(err)
1024+
}
1025+
if md.ContentType != "text/tomato" {
1026+
t.Error("Bad content type", md.ContentType)
1027+
}
1028+
if md.Bytes != CONTENT_SIZE {
1029+
t.Errorf("Bad length want 5 got %v", md.Bytes)
1030+
}
1031+
if md.Hash != CONTENT2_MD5 {
1032+
t.Errorf("Bad MD5 want %v got %v", CONTENT2_MD5, md.Hash)
1033+
}
1034+
}
1035+
9111036
func TestObjectPutBytes(t *testing.T) {
9121037
c, rollback := makeConnectionWithContainer(t)
9131038
defer rollback()

0 commit comments

Comments
 (0)