github.com/teepark/go-sysvipc@v0.0.0-20200817232735-d7ca6053ea29/shm_test.go (about)

     1  package sysvipc
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  	"syscall"
     7  	"testing"
     8  )
     9  
    10  func TestSHMErrors(t *testing.T) {
    11  	if _, err := GetSharedMem(0xDA7ABA5E, 64, nil); err != syscall.ENOENT {
    12  		t.Error("shmget without IPC_CREAT should have failed")
    13  	}
    14  
    15  	if _, err := (&SharedMem{5, 64}).Attach(nil); err != syscall.EINVAL && err != syscall.EIDRM {
    16  		t.Error("shmat on a made-up shmid should fail", err)
    17  	}
    18  
    19  	if err := (&SharedMem{5, 64}).Remove(); err != syscall.EINVAL && err != syscall.EIDRM {
    20  		t.Error("shmctl(IPC_RMID) on a made-up shmid should fail", err)
    21  	}
    22  
    23  	sm, err := GetSharedMem(0xDA7ABA5E, 64, &SHMFlags{
    24  		Create:    true,
    25  		Exclusive: true,
    26  		Perms:     0600,
    27  	})
    28  	if err != nil {
    29  		t.Fatal(err)
    30  	}
    31  	defer sm.Remove()
    32  	mnt, err := sm.Attach(nil)
    33  	if err != nil {
    34  		t.Fatal(err)
    35  	}
    36  	if err := mnt.Close(); err != nil {
    37  		t.Fatal(err)
    38  	}
    39  	if err := mnt.Close(); err == nil {
    40  		t.Error("double close should fail")
    41  	}
    42  }
    43  
    44  func TestReadAndWrite(t *testing.T) {
    45  	shmSetup(t)
    46  	defer shmTeardown(t)
    47  
    48  	s := "this is a test string"
    49  
    50  	_, err := mount.Write([]byte(s))
    51  	if err != nil {
    52  		t.Fatal(err)
    53  	}
    54  
    55  	_, err = mount.Seek(0, 0)
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  
    60  	holder := make([]byte, len(s))
    61  	_, err = mount.Read(holder)
    62  	if err != nil {
    63  		t.Error(err)
    64  	}
    65  
    66  	if string(holder) != s {
    67  		t.Errorf("mismatched text, got back %v", holder)
    68  	}
    69  
    70  	_, err = mount.Seek(int64(-len(s)), 2)
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  
    75  	b := make([]byte, len(s)*2)
    76  	i, err := mount.Read(b)
    77  	if err != io.EOF {
    78  		t.Error("a read that doesn't fill the buffer should give EOF", err)
    79  	}
    80  	if i != len(s) {
    81  		t.Error("wrong length", i)
    82  	}
    83  
    84  	_, err = mount.Seek(0, 2)
    85  	if err != nil {
    86  		t.Fatal(err)
    87  	}
    88  
    89  	i, err = mount.Read(b)
    90  	if err != io.EOF {
    91  		t.Error("a read that comes up empty should give EOF", err)
    92  	}
    93  	if i != 0 {
    94  		t.Error("wrong length", i)
    95  	}
    96  
    97  	i, err = mount.Write(b)
    98  	if err != io.ErrShortWrite {
    99  		t.Error("a write that couldn't complete should give ErrShortWrite", err)
   100  	}
   101  	if i != 0 {
   102  		t.Error("wrong length", i)
   103  	}
   104  
   105  	_, err = mount.Seek(0, 0)
   106  	if err != nil {
   107  		t.Fatal(err)
   108  	}
   109  
   110  	err = mount.AtomicWriteUint32(0x01020304)
   111  	if err != nil {
   112  		t.Fatal(err)
   113  	}
   114  
   115  	_, err = mount.Seek(0, 0)
   116  	if err != nil {
   117  		t.Fatal(err)
   118  	}
   119  
   120  	v, err := mount.AtomicReadUint32()
   121  	if err != nil {
   122  		t.Fatal(err)
   123  	}
   124  
   125  	if v != 0x01020304 {
   126  		t.Errorf("Got %v, expected %v", v, 0x01020304)
   127  	}
   128  }
   129  
   130  func TestSHMReadOnlyError(t *testing.T) {
   131  	shmSetup(t)
   132  	defer shmTeardown(t)
   133  
   134  	roat, err := shm.Attach(&SHMAttachFlags{ReadOnly: true})
   135  	if err != nil {
   136  		t.Fatal(err)
   137  	}
   138  
   139  	if _, err := roat.Write([]byte("ohai!")); err == nil {
   140  		t.Error("should error on write to a read-only mount", err)
   141  	}
   142  
   143  	if err := roat.WriteByte('+'); err == nil {
   144  		t.Error("should error on WriteByte to a read-only mount", err)
   145  	}
   146  }
   147  
   148  func TestSHMSeeks(t *testing.T) {
   149  	shmSetup(t)
   150  	defer shmTeardown(t)
   151  
   152  	i, err := mount.Seek(2048, 0)
   153  	if err != nil {
   154  		t.Fatal(err)
   155  	}
   156  	if i != 2048 {
   157  		t.Error("Seek to 2048 from the beginning should land at 2048", i)
   158  	}
   159  
   160  	j, err := mount.Seek(50, 1)
   161  	if err != nil {
   162  		t.Fatal(err)
   163  	}
   164  	if j != 2098 {
   165  		t.Error("Seek forward 50 should have landed at 2098", j)
   166  	}
   167  
   168  	k, err := mount.Seek(0, 2)
   169  	if err != nil {
   170  		t.Fatal(err)
   171  	}
   172  	if k != 4096 {
   173  		t.Error("Seek to end should land at 4096, the segment length", k)
   174  	}
   175  
   176  	_, err = mount.Seek(0, 3)
   177  	if err == nil {
   178  		t.Error("should fail on a bad 'whence'")
   179  	}
   180  
   181  	_, err = mount.Seek(-10, 0)
   182  	if err == nil {
   183  		t.Error("should fail when we end up at a negative index")
   184  	}
   185  
   186  	l, err := mount.Seek(7000, 0)
   187  	if err != nil {
   188  		t.Fatal(err)
   189  	}
   190  	if l != 4096 {
   191  		t.Error("should max out seeking to the end", l)
   192  	}
   193  }
   194  
   195  func TestSHMReadAndWriteByte(t *testing.T) {
   196  	shmSetup(t)
   197  	defer shmTeardown(t)
   198  
   199  	s := "test string"
   200  	for _, b := range []byte(s) {
   201  		if err := mount.WriteByte(b); err != nil {
   202  			t.Error(err)
   203  		}
   204  	}
   205  
   206  	if _, err := mount.Seek(0, 0); err != nil {
   207  		t.Fatal(err)
   208  	}
   209  
   210  	for i, b := range []byte(s) {
   211  		c, err := mount.ReadByte()
   212  		if err != nil {
   213  			t.Error(err)
   214  		}
   215  
   216  		if b != c {
   217  			t.Errorf("mismatched byte at position %d: %d vs %d", i, c, b)
   218  		}
   219  	}
   220  
   221  	if _, err := mount.Seek(0, 2); err != nil {
   222  		t.Fatal(err)
   223  	}
   224  
   225  	if _, err := mount.ReadByte(); err != io.EOF {
   226  		t.Error("attempt to ReadByte from the end should produce EOF", err)
   227  	}
   228  
   229  	if err := mount.WriteByte('+'); err != io.ErrShortWrite {
   230  		t.Error("attempt to WriteByte from the end should ErrShortWrite", err)
   231  	}
   232  }
   233  
   234  func TestUnreadByte(t *testing.T) {
   235  	shmSetup(t)
   236  	defer shmTeardown(t)
   237  
   238  	s := "abcdefg"
   239  
   240  	if _, err := mount.Write([]byte(s)); err != nil {
   241  		t.Fatal(err)
   242  	}
   243  
   244  	for i, c := range []byte(s) {
   245  		if _, err := mount.Seek(int64(i), 0); err != nil {
   246  			t.Fatal(err)
   247  		}
   248  
   249  		switch b, err := mount.ReadByte(); true {
   250  		case err != nil:
   251  			t.Error(err)
   252  		case b != c:
   253  			t.Error(i, c, b)
   254  		}
   255  
   256  		if err := mount.UnreadByte(); err != nil {
   257  			t.Error(err)
   258  		}
   259  
   260  		switch b, err := mount.ReadByte(); true {
   261  		case err != nil:
   262  			t.Error(err)
   263  		case b != c:
   264  			t.Error(i, c, b)
   265  		}
   266  	}
   267  
   268  	if _, err := mount.Seek(0, 0); err != nil {
   269  		t.Fatal(err)
   270  	}
   271  
   272  	if err := mount.UnreadByte(); err == nil {
   273  		t.Error("UnreadByte from beginning should fail", err)
   274  	}
   275  }
   276  
   277  func TestSHMStat(t *testing.T) {
   278  	shmSetup(t)
   279  	defer shmTeardown(t)
   280  
   281  	info, err := shm.Stat()
   282  	if err != nil {
   283  		t.Fatal(err)
   284  	}
   285  	if info.Perms.Mode&0777 != 0600 {
   286  		t.Error("wrong permissions", info.Perms.Mode)
   287  	}
   288  	if info.Perms.OwnerUID != os.Getuid() {
   289  		t.Error("wrong owner")
   290  	}
   291  	if info.Perms.CreatorUID != os.Getuid() {
   292  		t.Error("wrong creator")
   293  	}
   294  	if info.SegmentSize != 4096 {
   295  		t.Error("wrong size:", info.SegmentSize)
   296  	}
   297  	if info.CreatorPID != os.Getpid() {
   298  		t.Error("wrong creator pid")
   299  	}
   300  	if info.LastUserPID != os.Getpid() {
   301  		t.Error("wrong last user pid")
   302  	}
   303  	if info.CurrentAttaches != 1 {
   304  		t.Error("wrong number of attaches:", info.CurrentAttaches)
   305  	}
   306  
   307  	mnt2, err := shm.Attach(nil)
   308  	if err != nil {
   309  		t.Fatal(err)
   310  	}
   311  	defer mnt2.Close()
   312  
   313  	info, err = shm.Stat()
   314  	if err != nil {
   315  		t.Fatal(err)
   316  	}
   317  	if info.CurrentAttaches != 2 {
   318  		t.Error("didn't get the extra attach?", info.CurrentAttaches)
   319  	}
   320  }
   321  
   322  func TestSHMSet(t *testing.T) {
   323  	shmSetup(t)
   324  	defer shmTeardown(t)
   325  
   326  	inf, err := shm.Stat()
   327  	if err != nil {
   328  		t.Fatal(err)
   329  	}
   330  
   331  	err = shm.Set(&SHMInfo{
   332  		Perms: IpcPerms{
   333  			OwnerUID: inf.Perms.OwnerUID,
   334  			OwnerGID: inf.Perms.OwnerGID,
   335  			Mode:     0644,
   336  		},
   337  	})
   338  	if err != nil {
   339  		t.Fatal(err)
   340  	}
   341  
   342  	inf, err = shm.Stat()
   343  	if err != nil {
   344  		t.Fatal(err)
   345  	}
   346  
   347  	if inf.Perms.Mode&0777 != 0644 {
   348  		t.Error("mode change didn't take")
   349  	}
   350  }
   351  
   352  var (
   353  	shm   *SharedMem
   354  	mount *SharedMemMount
   355  )
   356  
   357  func shmSetup(t *testing.T) {
   358  	mem, err := GetSharedMem(0xDA7ABA5E, 4096, &SHMFlags{
   359  		Create:    true,
   360  		Exclusive: true,
   361  		Perms:     0600,
   362  	})
   363  	if err != nil {
   364  		t.Fatal(err)
   365  	}
   366  	shm = mem
   367  
   368  	mnt, err := shm.Attach(nil)
   369  	if err != nil {
   370  		t.Fatal(err)
   371  	}
   372  	mount = mnt
   373  
   374  	err = shm.Remove()
   375  	if err != nil {
   376  		t.Fatal(err)
   377  	}
   378  }
   379  
   380  func shmTeardown(t *testing.T) {
   381  	mount.Close()
   382  }