github.com/arduino/arduino-cloud-cli@v0.0.0-20240517070944-e7a449561083/command/ota/massupload_test.go (about)

     1  package ota
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"os"
     7  	"strings"
     8  	"testing"
     9  
    10  	otaapi "github.com/arduino/arduino-cloud-cli/internal/ota-api"
    11  	iotclient "github.com/arduino/iot-client-go"
    12  	"github.com/gofrs/uuid"
    13  	"github.com/stretchr/testify/assert"
    14  )
    15  
    16  const testFilename = "testdata/empty.bin"
    17  const cloudFirmwareFilename = "testdata/cloud.bin"
    18  
    19  type deviceUploaderTest struct {
    20  	deviceOTA func(ctx context.Context, id string, file *os.File, expireMins int) error
    21  }
    22  
    23  func (d *deviceUploaderTest) DeviceOTA(ctx context.Context, id string, file *os.File, expireMins int) error {
    24  	return d.deviceOTA(ctx, id, file, expireMins)
    25  }
    26  
    27  type otaStatusGetterTest struct{}
    28  
    29  func (s *otaStatusGetterTest) GetOtaLastStatusByDeviceID(deviceID string) (*otaapi.OtaStatusList, error) {
    30  	ota := otaapi.Ota{
    31  		ID:        uuid.Must(uuid.NewV4()).String(),
    32  		Status:    "in_progress",
    33  		StartedAt: "2021-09-01T12:00:00Z",
    34  	}
    35  	response := &otaapi.OtaStatusList{
    36  		Ota: []otaapi.Ota{ota},
    37  	}
    38  	return response, nil
    39  }
    40  
    41  func TestRun(t *testing.T) {
    42  	var (
    43  		failPrefix = "00000000"
    44  		failID1    = failPrefix + "-b39d-47a2-adf3-d26cdf474707"
    45  		failID2    = failPrefix + "-9efd-4670-a478-df76ebdeeb4f"
    46  		okPrefix   = "11111111"
    47  		okID1      = okPrefix + "-4838-4f46-8930-d735c5b76cd1"
    48  		okID2      = okPrefix + "-003f-42f9-a80c-85a1de36753b"
    49  		okID3      = okPrefix + "-dac4-4a6a-80a4-698062fe2af5"
    50  	)
    51  	mockClient := &deviceUploaderTest{
    52  		deviceOTA: func(ctx context.Context, id string, file *os.File, expireMins int) error {
    53  			if strings.Split(id, "-")[0] == failPrefix {
    54  				return errors.New("err")
    55  			}
    56  			return nil
    57  		},
    58  	}
    59  	mockStatusClient := &otaStatusGetterTest{}
    60  
    61  	devs := []string{okID1, failID1, okID2, failID2, okID3}
    62  	res := run(context.TODO(), mockClient, mockStatusClient, devs, testFilename, 0)
    63  	if len(res) != len(devs) {
    64  		t.Errorf("expected %d results, got %d", len(devs), len(res))
    65  	}
    66  
    67  	for _, r := range res {
    68  		pre := strings.Split(r.ID, "-")[0]
    69  		if pre == okPrefix && r.Err != nil {
    70  			t.Errorf("device %s expected to succeed, but got error %s", r.ID, r.Err.Error())
    71  		}
    72  		if pre == failPrefix && r.Err == nil {
    73  			t.Errorf("device %s expected to fail, but got no error", r.ID)
    74  		}
    75  	}
    76  }
    77  
    78  type deviceListerTest struct {
    79  	list []iotclient.ArduinoDevicev2
    80  }
    81  
    82  func (d *deviceListerTest) DeviceList(ctx context.Context, tags map[string]string) ([]iotclient.ArduinoDevicev2, error) {
    83  	return d.list, nil
    84  }
    85  
    86  func TestValidateDevices(t *testing.T) {
    87  	var (
    88  		correctFQBN = "arduino:samd:nano_33_iot"
    89  		wrongFQBN   = "arduino:samd:mkrwifi1010"
    90  
    91  		idCorrect1 = "88d683a4-525e-423d-bad2-66a54d3585df"
    92  		idCorrect2 = "84b593fa-86dd-4954-904d-60f657158715"
    93  		idNotValid = "e3a3a667-a859-4317-be97-a61fb6f63487"
    94  		idNotFound = "deb17b7f-b39d-47a2-adf3-d26cdf474707"
    95  	)
    96  
    97  	mockDeviceList := deviceListerTest{
    98  		list: []iotclient.ArduinoDevicev2{
    99  			{Id: idCorrect1, Fqbn: correctFQBN},
   100  			{Id: idCorrect2, Fqbn: correctFQBN},
   101  			{Id: idNotValid, Fqbn: wrongFQBN},
   102  		},
   103  	}
   104  
   105  	ids := []string{
   106  		idCorrect1,
   107  		idNotFound,
   108  		idCorrect2,
   109  		idNotValid,
   110  	}
   111  	v, i, err := validateDevices(context.TODO(), &mockDeviceList, ids, correctFQBN)
   112  	if err != nil {
   113  		t.Errorf("unexpected error: %s", err.Error())
   114  	}
   115  
   116  	if len(v) != 2 {
   117  		t.Errorf("expected 2 valid devices, but found %d: %v", len(v), v)
   118  	}
   119  
   120  	if len(i) != 2 {
   121  		t.Errorf("expected 2 invalid devices, but found %d: %v", len(i), i)
   122  	}
   123  }
   124  
   125  func TestValidateBuildOtaFile(t *testing.T) {
   126  
   127  	file, tmp, err := buildOtaFile(&MassUploadParams{
   128  		File:             cloudFirmwareFilename,
   129  		DoNotApplyHeader: false,
   130  		FQBN:             "arduino:samd:nano_33_iot",
   131  	})
   132  	assert.Nil(t, err)
   133  	assert.NotNil(t, file)
   134  	assert.True(t, strings.HasSuffix(file, "temp.ota"))
   135  	assert.NotEmpty(t, tmp)
   136  	defer os.RemoveAll(tmp)
   137  }
   138  
   139  func TestValidateBuildOtaFile_whenNoHeaderIsRequested(t *testing.T) {
   140  
   141  	file, tmp, err := buildOtaFile(&MassUploadParams{
   142  		File:             cloudFirmwareFilename,
   143  		DoNotApplyHeader: true,
   144  		FQBN:             "arduino:samd:nano_33_iot",
   145  	})
   146  	assert.Nil(t, err)
   147  	assert.NotNil(t, file)
   148  	assert.Equal(t, cloudFirmwareFilename, file)
   149  	assert.Empty(t, tmp)
   150  }