You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

118 lines
3.6 KiB

package recoveryrequest
import (
"bytes"
"os"
"path/filepath"
"testing"
)
func TestEncodeMatchesRockchipBootloaderMessageLayout(t *testing.T) {
encoded, err := Encode("fw-0123456789abcdef")
if err != nil {
t.Fatal(err)
}
if len(encoded) != Size {
t.Fatalf("size = %d, want %d", len(encoded), Size)
}
if got := field(encoded, commandOffset, commandSize); got != Command {
t.Fatalf("command = %q", got)
}
if got := field(encoded, statusOffset, statusSize); got != "" {
t.Fatalf("status = %q", got)
}
if got := field(encoded, recoveryOffset, recoverySize); got != "recovery\n--tera-update\n--operation=fw-0123456789abcdef\n" {
t.Fatalf("recovery = %q", got)
}
if got := field(encoded, stageOffset, stageSize); got != "" {
t.Fatalf("stage = %q", got)
}
message, err := Decode(encoded)
if err != nil || message.OperationID != "fw-0123456789abcdef" {
t.Fatalf("Decode = %+v, %v", message, err)
}
}
func TestWriteAtTouchesOnlyTheBCBAndReadsBack(t *testing.T) {
device := bytes.NewReader(bytes.Repeat([]byte{0xa5}, int(Offset)+Size+4096))
buffer := &memoryDevice{data: make([]byte, device.Size())}
if _, err := device.ReadAt(buffer.data, 0); err != nil {
t.Fatal(err)
}
encoded, _ := Encode("operation-1")
if err := WriteAt(buffer, encoded); err != nil {
t.Fatal(err)
}
if !bytes.Equal(buffer.data[:Offset], bytes.Repeat([]byte{0xa5}, int(Offset))) {
t.Fatal("bytes before the BCB changed")
}
if !bytes.Equal(buffer.data[Offset+Size:], bytes.Repeat([]byte{0xa5}, len(buffer.data)-int(Offset)-Size)) {
t.Fatal("bytes after the BCB changed")
}
message, err := ReadAt(buffer)
if err != nil || message.OperationID != "operation-1" {
t.Fatalf("ReadAt = %+v, %v", message, err)
}
}
func TestRejectsInvalidOrForeignMessages(t *testing.T) {
for _, value := range []string{"", " space", "slash/value", string(bytes.Repeat([]byte{'a'}, 65))} {
if _, err := Encode(value); err == nil {
t.Fatalf("Encode(%q) succeeded", value)
}
}
foreign := make([]byte, Size)
copy(foreign, "boot-recovery")
copy(foreign[recoveryOffset:], "recovery\n--wipe_data\n")
if _, err := Decode(foreign); err == nil {
t.Fatal("foreign recovery message was accepted")
}
if _, err := Decode(Clear()); err == nil {
t.Fatal("cleared message was accepted")
}
}
func TestClearIsExactZeroRecord(t *testing.T) {
cleared := Clear()
if len(cleared) != Size {
t.Fatalf("Clear size = %d, want %d", len(cleared), Size)
}
if !bytes.Equal(cleared, make([]byte, Size)) {
t.Fatal("Clear returned a non-zero BCB byte")
}
}
func TestWriteRequestFileRequiresClearRecordAndPreservesSurroundingBytes(t *testing.T) {
path := filepath.Join(t.TempDir(), "misc.img")
contents := bytes.Repeat([]byte{0xa5}, int(Offset)+Size+4096)
copy(contents[Offset:Offset+Size], Clear())
if err := os.WriteFile(path, contents, 0o600); err != nil {
t.Fatal(err)
}
if err := WriteRequestFile(path, "operation-1", true); err != nil {
t.Fatal(err)
}
updated, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(updated[:Offset], contents[:Offset]) || !bytes.Equal(updated[Offset+Size:], contents[Offset+Size:]) {
t.Fatal("WriteRequestFile changed bytes outside the BCB")
}
if IsClear(updated[Offset : Offset+Size]) {
t.Fatal("request remained clear")
}
if err := WriteRequestFile(path, "operation-2", true); err == nil {
t.Fatal("non-cleared recovery request was overwritten")
}
}
type memoryDevice struct{ data []byte }
func (d *memoryDevice) ReadAt(p []byte, off int64) (int, error) {
return copy(p, d.data[int(off):]), nil
}
func (d *memoryDevice) WriteAt(p []byte, off int64) (int, error) {
return copy(d.data[int(off):], p), nil
}