| // Copyright (C) 2016 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package memory |
| |
| import ( |
| "bytes" |
| "io" |
| "testing" |
| |
| "android.googlesource.com/platform/tools/gpu/framework/assert" |
| _ "android.googlesource.com/platform/tools/gpu/framework/binary/any" |
| "android.googlesource.com/platform/tools/gpu/gapid/database" |
| "android.googlesource.com/platform/tools/gpu/framework/id" |
| ) |
| |
| // readFully returns the entire data produced by the given Reader, by reading up to maxRead bytes at a time. |
| func readFully(r io.Reader, maxRead int) ([]byte, error) { |
| var b bytes.Buffer |
| readBuffer := make([]byte, maxRead) |
| for { |
| n, err := r.Read(readBuffer) |
| b.Write(readBuffer[:n]) |
| if err == io.EOF { |
| return b.Bytes(), nil |
| } else if err != nil { |
| return b.Bytes(), err |
| } |
| } |
| } |
| |
| func checkSlice(t *testing.T, d database.Database, s Slice, expected []byte) { |
| ctx := assert.Context(t) |
| assert.With(ctx).That(s.Size()).Equals(uint64(len(expected))) |
| |
| for _, offset := range []uint64{0, 1, s.Size()-1, s.Size()} { |
| got := make([]byte, len(expected)-int(offset)) |
| err := s.Get(ctx, d, offset, got) |
| assert.With(ctx).ThatError(err).Succeeded() |
| assert.With(ctx).ThatSlice(got).Equals(expected[offset:]) |
| } |
| |
| for _, maxReadSize := range []int{1, 2, 3, 512} { |
| got, err := readFully(s.NewReader(ctx, d), maxReadSize) |
| assert.With(ctx).ThatError(err).Succeeded() |
| assert.With(ctx).ThatSlice(got).Equals(expected) |
| } |
| } |
| |
| func TestBlobSlice(t *testing.T) { |
| data := Blob([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) |
| for _, test := range []struct { |
| rng Range |
| expected []byte |
| }{ |
| {Range{Base: 0, Size: 10}, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}, |
| {Range{Base: 3, Size: 3}, []byte{3, 4, 5}}, |
| {Range{Base: 6, Size: 3}, []byte{6, 7, 8}}, |
| } { |
| checkSlice(t, nil, data.Slice(test.rng), test.expected) |
| } |
| } |
| |
| // Write layout: |
| // 0 1 2 3 4 5 |
| // ╔════╤════╤════╤════╤════╗────┐ |
| // 0 ║ 10 │ 11 │ 12 │ 13 │ 14 ║ │ |
| // ╚════╧════╧════╧════╧════╝────┘ |
| // ╔════╤════╤════╤════╤════╗────┐ |
| // 1 ║ 20 │ 21 │ 22 │ 23 │ 24 ║ │ |
| // ╚════╧════╧════╧════╧════╝────┘ |
| // ╔════╤════╗────┬────┬────┬────┐ |
| // 2 ║ 30 │ 31 ║ │ │ │ │ |
| // ╚════╧════╝────┴────┴────┴────┘ |
| // ╔════╤════╤════╤════╤════╤════╗ |
| // 3 ║ 40 │ 41 │ 42 │ 43 │ 44 │ 45 ║ |
| // ╚════╧════╧════╧════╧════╧════╝ |
| func TestPoolBlobWriteRead(t *testing.T) { |
| p := Pool{} |
| for _, test := range []struct { |
| data Slice |
| expected []byte |
| }{ |
| {Blob([]byte{10, 11, 12, 13, 14}), []byte{10, 11, 12, 13, 14, 0}}, |
| {Blob([]byte{20, 21, 22, 23, 24}), []byte{20, 21, 22, 23, 24, 0}}, |
| {Blob([]byte{30, 31}), []byte{30, 31, 22, 23, 24, 0}}, |
| {Blob([]byte{40, 41, 42, 43, 44, 45}), []byte{40, 41, 42, 43, 44, 45}}, |
| } { |
| p.Write(0, test.data) |
| |
| checkSlice(t, nil, p.Slice(Range{Base: 0, Size: 6}), test.expected) |
| } |
| } |
| |
| // Write layout: |
| // 0 1 2 3 4 5 6 7 8 9 10 11 |
| // ┌────╔════╤════╤════╗────┬────┬────┬────┬────┬────┬────┬────┐ |
| // 0 │ ║ 10 │ 11 │ 12 ║ │ │ │ │ │ │ │ │ |
| // └────╚════╧════╧════╝────┴────┴────┴────┴────┴────┴────┴────┘ |
| // ┌────┬────┬────┬────┬────┬────┬────╔════╤════╤════╤════╗────┐ |
| // 1 │ │ │ │ │ │ │ ║ 20 │ 21 │ 22 │ 23 ║ │ |
| // └────┴────┴────┴────┴────┴────┴────╚════╧════╧════╧════╝────┘ |
| // ┌────┬────╔════╤════╗────┬────┬────┬────┬────┬────┬────┬────┐ |
| // 2 │ │ ║ 30 │ 31 ║ │ │ │ │ │ │ │ │ |
| // └────┴────╚════╧════╝────┴────┴────┴────┴────┴────┴────┴────┘ |
| // ┌────┬────╔════╤════╤════╗────┬────┬────┬────┬────┬────┬────┐ |
| // 3 │ │ ║ 40 │ 41 │ 42 ║ │ │ │ │ │ │ │ |
| // └────┴────╚════╧════╧════╝────┴────┴────┴────┴────┴────┴────┘ |
| // ┌────┬────┬────┬────┬────┬────┬────┬────╔════╗────┬────┬────┐ |
| // 4 │ │ │ │ │ │ │ │ ║ 50 ║ │ │ │ |
| // └────┴────┴────┴────┴────┴────┴────┴────╚════╝────┴────┴────┘ |
| // |
| func TestMemoryBlobWriteReadScattered(t *testing.T) { |
| p := Pool{} |
| p.Write(1, Blob([]byte{10, 11, 12})) |
| p.Write(7, Blob([]byte{20, 21, 22, 23})) |
| p.Write(2, Blob([]byte{30, 31})) |
| p.Write(2, Blob([]byte{40, 41, 42})) |
| p.Write(8, Blob([]byte{50})) |
| |
| for _, test := range []struct { |
| rng Range |
| expected []byte |
| }{ |
| {Range{Base: 0, Size: 12}, []byte{0, 10, 40, 41, 42, 00, 00, 20, 50, 22, 23, 00}}, |
| {Range{Base: 1, Size: 10}, []byte{10, 40, 41, 42, 00, 00, 20, 50, 22, 23}}, |
| {Range{Base: 2, Size: 3}, []byte{40, 41, 42}}, |
| {Range{Base: 3, Size: 6}, []byte{41, 42, 0, 0, 20, 50}}, |
| {Range{Base: 3, Size: 7}, []byte{41, 42, 0, 0, 20, 50, 22}}, |
| {Range{Base: 5, Size: 2}, []byte{0, 0}}, |
| {Range{Base: 8, Size: 1}, []byte{50}}, |
| } { |
| checkSlice(t, nil, p.Slice(test.rng), test.expected) |
| } |
| |
| } |
| |
| // Write layout: |
| // 0 1 2 3 4 5 6 7 8 9 10 11 |
| // ┌────╔════╤════╤════╗────┬────┬────┬────┬────┬────┬────┬────┐ |
| // 0 │ ║A 10│ 11 │ 12 ║ │ │ │ │ │ │ │ │ |
| // └────╚════╧════╧════╝────┴────┴────┴────┴────┴────┴────┴────┘ |
| // ┌────┬────┬────┬────┬────┬────┬────╔════╤════╤════╤════╗────┐ |
| // 1 │ │ │ │ │ │ │ ║B 20│ 21 │ 22 │ 23 ║ │ |
| // └────┴────┴────┴────┴────┴────┴────╚════╧════╧════╧════╝────┘ |
| // ┌────┬────╔════╤════╗────┬────┬────┬────┬────┬────┬────┬────┐ |
| // 2 │ │ ║C 30│ 31 ║ │ │ │ │ │ │ │ │ |
| // └────┴────╚════╧════╝────┴────┴────┴────┴────┴────┴────┴────┘ |
| // ┌────┬────╔════╤════╤════╗────┬────┬────┬────┬────┬────┬────┐ |
| // 3 │ │ ║D 40│ 41 │ 42 ║ │ │ │ │ │ │ │ |
| // └────┴────╚════╧════╧════╝────┴────┴────┴────┴────┴────┴────┘ |
| // ┌────┬────┬────┬────┬────┬────┬────┬────╔════╗────┬────┬────┐ |
| // 4 │ │ │ │ │ │ │ │ ║E 50║ │ │ │ |
| // └────┴────┴────┴────┴────┴────┴────┴────╚════╝────┴────┴────┘ |
| // |
| func TestMemoryResourceWriteReadScattered(t *testing.T) { |
| ctx := assert.Context(t) |
| d := database.NewInMemory(nil) |
| resA, _ := database.Store(ctx, []byte{10, 11, 12}, d) |
| resB, _ := database.Store(ctx, []byte{20, 21, 22, 23}, d) |
| resC, _ := database.Store(ctx, []byte{30, 31}, d) |
| resD, _ := database.Store(ctx, []byte{40, 41, 42}, d) |
| resE, _ := database.Store(ctx, []byte{50}, d) |
| |
| p := Pool{} |
| p.Write(1, Resource(resA, 3)) |
| p.Write(7, Resource(resB, 4)) |
| p.Write(2, Resource(resC, 2)) |
| p.Write(2, Resource(resD, 3)) |
| p.Write(8, Resource(resE, 1)) |
| |
| for _, test := range []struct { |
| rng Range |
| expected []byte |
| }{ |
| {Range{Base: 0, Size: 12}, []byte{0, 10, 40, 41, 42, 00, 00, 20, 50, 22, 23, 00}}, |
| {Range{Base: 1, Size: 10}, []byte{10, 40, 41, 42, 00, 00, 20, 50, 22, 23}}, |
| {Range{Base: 2, Size: 3}, []byte{40, 41, 42}}, |
| {Range{Base: 5, Size: 2}, []byte{0, 0}}, |
| {Range{Base: 8, Size: 1}, []byte{50}}, |
| } { |
| slice := p.Slice(test.rng) |
| checkSlice(t, d, slice, test.expected) |
| |
| gotID, err := slice.ResourceID(ctx, d) |
| assert.With(ctx).ThatError(err).Succeeded() |
| |
| expectedID, _ := database.Store(ctx, test.expected, d) |
| assert.With(ctx).That(gotID).Equals(expectedID) |
| } |
| } |
| |
| func TestPoolSliceReaderErrorPropagation(t *testing.T) { |
| ctx := assert.Context(t) |
| p := Pool{} |
| p.Write(2, Resource(id.ID{}, 5)) |
| |
| got, err := readFully(p.Slice(Range{Base:0, Size:10}).NewReader(ctx, database.NewInMemory(nil)), 512) |
| assert.With(ctx).That(len(got)).Equals(2) |
| assert.With(ctx).ThatError(err).Failed() |
| } |
| |
| |
| // Write layout: |
| // innerPool: |
| // 0 1 2 |
| // ┌────┬────┬────┐ |
| // 0 │ 4 │ 55 │ 66 │ |
| // └────┴────┴────┘ |
| // │ │ │ |
| // midPool: │ │ │ |
| // 0 1 2 3 4 5 6 7 |
| // ┌────╔════╤════╤════╗────┬────┬────┬────┐ |
| // 0 │ ║ 4i │ 55i│ 66i║ │ │ │ │ |
| // └────╚════╧════╧════╝────┴────┴────┴────┘ |
| // ┌────┬────╔════╤════╤════╤════╗────┬────┐ |
| // 1 │ │ ║ 5 │ 6 │ 7 │ 88 ║ │ │ |
| // └────┴────╚════╧════╧════╧════╝────┴────┘ |
| // ┌────┬────┬────┬────┬────╔════╤════╤════╗ |
| // 2 │ │ │ │ │ ║ 8r │ 9r │ 10r║ |
| // └────┴────┴────┴────┴────╚════╧════╧════╝ |
| // │ │ │ │ │ │ │ |
| // outerPool: │ │ │ │ │ │ │ |
| // 0 1 2 3 4 5 6 7 8 9 10 |
| // ┌────╔════╤════╤════╤════╗────┬────┬────┬────┬────┬────┐ |
| // 0 │ ║ 1 │ 2 │ 3 │ 44 ║ │ │ │ │ │ │ |
| // └────╚════╧════╧════╧════╝────┴────┴────┴────┴────┴────┘ |
| // │ │ │ │ │ │ │ |
| // ┌────┬────┬────┬────╔════╤════╤════╤════╤════╤════╤════╗ |
| // 1 │ │ │ │ ║ 4m │ 5m │ 6m │ 7m │ 8m │ 9m │ 10m║ |
| // └────┴────┴────┴────╚════╧════╧════╧════╧════╧════╧════╝ |
| // |
| func TestSliceNesting(t *testing.T) { |
| ctx := assert.Context(t) |
| d := database.NewInMemory(nil) |
| |
| innerPool := Pool{} |
| innerPool.Write(0, Blob([]byte{4, 55, 66})) |
| |
| midPool := Pool{} |
| midPool.Write(1, innerPool.Slice(Range{Size:3})) |
| midPool.Write(2, Blob([]byte{5, 6, 7, 88})) |
| res, _ := database.Store(ctx, []byte{8, 9, 10}, d) |
| midPool.Write(5, Resource(res, 3)) |
| |
| outerPool := Pool{} |
| outerPool.Write(1, Blob([]byte{1, 2, 3, 44})) |
| outerPool.Write(4, midPool.Slice(Range{Base:1, Size:7})) |
| |
| checkSlice(t, d, outerPool.Slice(Range{Size:11}), []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) |
| } |