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 }