github.com/transparency-dev/armored-witness-applet@v0.1.1/trusted_applet/internal/storage/slots/slots_test.go (about)

     1  // Copyright 2022 The Armored Witness Applet authors. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package slots
    16  
    17  import (
    18  	"fmt"
    19  	"testing"
    20  
    21  	"github.com/google/go-cmp/cmp"
    22  	"github.com/transparency-dev/armored-witness-applet/trusted_applet/internal/storage/testonly"
    23  )
    24  
    25  func TestOpenPartition(t *testing.T) {
    26  	type slotGeo struct {
    27  		Start  uint
    28  		Length uint
    29  	}
    30  	toSlotGeo := func(in []Slot) []slotGeo {
    31  		r := make([]slotGeo, len(in))
    32  		for i := range in {
    33  			r[i] = slotGeo{
    34  				Start:  in[i].start,
    35  				Length: in[i].length,
    36  			}
    37  		}
    38  		return r
    39  	}
    40  
    41  	const devBlockSize = 32
    42  
    43  	for _, test := range []struct {
    44  		name      string
    45  		geo       Geometry
    46  		wantErr   bool
    47  		wantSlots []slotGeo
    48  	}{
    49  		{
    50  			name: "free space remaining",
    51  			geo: Geometry{
    52  				Start:       10,
    53  				Length:      10,
    54  				SlotLengths: []uint{1, 1, 2, 4},
    55  			},
    56  			wantSlots: []slotGeo{
    57  				{Start: 10, Length: 1},
    58  				{Start: 11, Length: 1},
    59  				{Start: 12, Length: 2},
    60  				{Start: 14, Length: 4},
    61  			},
    62  		}, {
    63  			name: "fully allocated",
    64  			geo: Geometry{
    65  				Start:       10,
    66  				Length:      10,
    67  				SlotLengths: []uint{1, 1, 2, 4, 2},
    68  			},
    69  			wantSlots: []slotGeo{
    70  				{Start: 10, Length: 1},
    71  				{Start: 11, Length: 1},
    72  				{Start: 12, Length: 2},
    73  				{Start: 14, Length: 4},
    74  				{Start: 18, Length: 2},
    75  			},
    76  		}, {
    77  			name: "over allocated",
    78  			geo: Geometry{
    79  				Start:       10,
    80  				Length:      10,
    81  				SlotLengths: []uint{1, 1, 2, 4, 3},
    82  			},
    83  			wantErr: true,
    84  		},
    85  	} {
    86  		t.Run(test.name, func(t *testing.T) {
    87  			dev := testonly.NewMemDev(t, devBlockSize)
    88  			p, err := OpenPartition(dev, test.geo)
    89  			if gotErr := err != nil; gotErr != test.wantErr {
    90  				t.Fatalf("Got %v, wantErr %t", err, test.wantErr)
    91  			}
    92  			if test.wantErr {
    93  				return
    94  			}
    95  			if diff := cmp.Diff(toSlotGeo(p.slots), test.wantSlots); diff != "" {
    96  				t.Fatalf("Got diff: %s", diff)
    97  			}
    98  		})
    99  	}
   100  }
   101  
   102  func memPartition(t *testing.T) (*Partition, *testonly.MemDev) {
   103  	t.Helper()
   104  	md := testonly.NewMemDev(t, 32)
   105  	geo := Geometry{
   106  		Start:       10,
   107  		Length:      10,
   108  		SlotLengths: []uint{1, 1, 2, 4},
   109  	}
   110  	p, err := OpenPartition(md, geo)
   111  	if err != nil {
   112  		t.Fatalf("Failed to create mem partition: %v", err)
   113  	}
   114  	return p, md
   115  }
   116  
   117  func TestOpenSlot(t *testing.T) {
   118  	p, _ := memPartition(t)
   119  	for _, test := range []struct {
   120  		name    string
   121  		slot    uint
   122  		wantErr bool
   123  	}{
   124  		{
   125  			name: "works",
   126  			slot: 0,
   127  		}, {
   128  			name:    "invalid slot: too big",
   129  			slot:    uint(len(p.slots)),
   130  			wantErr: true,
   131  		},
   132  	} {
   133  		t.Run(test.name, func(t *testing.T) {
   134  			_, err := p.Open(test.slot)
   135  			if gotErr := err != nil; gotErr != test.wantErr {
   136  				t.Fatalf("Failed to open slot: %v", err)
   137  			}
   138  		})
   139  	}
   140  }
   141  
   142  func TestErase(t *testing.T) {
   143  	p, _ := memPartition(t)
   144  
   145  	// Create some data in each slot
   146  	for i := 0; i < p.NumSlots(); i++ {
   147  		s, err := p.Open(uint(i))
   148  		if err != nil {
   149  			t.Fatalf("Failed to open slot %d: %v", i, err)
   150  		}
   151  		s.Write([]byte(fmt.Sprintf("data for slot %d", i)))
   152  	}
   153  
   154  	// Verify slots contain _something_
   155  	for i := 0; i < p.NumSlots(); i++ {
   156  		d, r := openAndRead(t, p, uint(i))
   157  		if got, want := r, uint32(1); got != want {
   158  			t.Fatalf("Got data with revision %d, want %d", got, want)
   159  		}
   160  		if len(d) == 0 {
   161  			t.Fatal("Got unexpected zero length data")
   162  		}
   163  	}
   164  
   165  	// Erase all the slots
   166  	if err := p.Erase(); err != nil {
   167  		t.Fatalf("Failed to erase partition: %v", err)
   168  	}
   169  
   170  	// All slots should now be empty
   171  	for i := 0; i < p.NumSlots(); i++ {
   172  		d, r := openAndRead(t, p, uint(i))
   173  		if got, want := r, uint32(0); got != want {
   174  			t.Fatalf("Got data with revision %d, want %d", got, want)
   175  		}
   176  		if len(d) != 0 {
   177  			t.Fatalf("Got unexpected data: %x", d)
   178  		}
   179  	}
   180  }
   181  
   182  func openAndRead(t *testing.T, p *Partition, i uint) ([]byte, uint32) {
   183  	t.Helper()
   184  	s, err := p.Open(uint(i))
   185  	if err != nil {
   186  		t.Fatalf("Failed to open slot %d: %v", i, err)
   187  	}
   188  	d, r, err := s.Read()
   189  	if err != nil {
   190  		t.Fatalf("Failed to read slot %d: %v", i, err)
   191  	}
   192  	return d, r
   193  }