github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/quality/morqa_transport_test.go (about)

     1  /*
     2   * Copyright (C) 2019 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package quality
    19  
    20  import (
    21  	"fmt"
    22  	"io"
    23  	"net/http"
    24  	"net/http/httptest"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/stretchr/testify/assert"
    29  	"google.golang.org/protobuf/proto"
    30  
    31  	"github.com/mysteriumnetwork/metrics"
    32  	"github.com/mysteriumnetwork/node/core/location/locationstate"
    33  	"github.com/mysteriumnetwork/node/identity"
    34  )
    35  
    36  var (
    37  	eventStartup = Event{
    38  		EventName:   unlockEventName,
    39  		Application: appInfo{Version: "test version"},
    40  		Context:     "0x1234567890abcdef",
    41  	}
    42  
    43  	signerFactory = func(id identity.Identity) identity.Signer {
    44  		return &identity.SignerFake{}
    45  	}
    46  )
    47  
    48  func TestMORQATransport_SendEvent_HandlesSuccess(t *testing.T) {
    49  	var events metrics.SignedBatch
    50  
    51  	server := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
    52  		body, _ := io.ReadAll(request.Body)
    53  		_ = proto.Unmarshal(body, &events)
    54  		response.WriteHeader(http.StatusAccepted)
    55  	}))
    56  
    57  	morqa := NewMorqaClient(httpClient, server.URL, signerFactory)
    58  
    59  	go morqa.Start()
    60  	defer morqa.Stop()
    61  
    62  	transport := &morqaTransport{morqaClient: morqa, lp: &mockLocationResolver{}}
    63  
    64  	err := transport.SendEvent(eventStartup)
    65  	assert.NoError(t, err)
    66  
    67  	assert.Eventually(t, func() bool {
    68  		morqa.sendAll()
    69  
    70  		return len(events.Batch.Events) > 0
    71  	}, 2*time.Second, 10*time.Millisecond)
    72  
    73  	assert.Exactly(
    74  		t,
    75  		"c2lnbmVkChAiDgoMdGVzdCB2ZXJzaW9u",
    76  		events.Signature,
    77  	)
    78  
    79  	assert.Exactly(
    80  		t,
    81  		&metrics.Event{
    82  			IsProvider: false,
    83  			TargetId:   "",
    84  			Version: &metrics.VersionPayload{
    85  				Version: "test version",
    86  			},
    87  		},
    88  		events.Batch.Events[0],
    89  	)
    90  }
    91  
    92  func TestMORQAT_sendMetrics_HandlesErrorsWithMessages(t *testing.T) {
    93  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    94  		w.WriteHeader(http.StatusBadRequest)
    95  		_, _ = w.Write([]byte(`{
    96  			"message": "invalid payload given"
    97  		}`))
    98  	}))
    99  
   100  	morqa := NewMorqaClient(httpClient, server.URL, signerFactory)
   101  	morqa.addMetric(metric{
   102  		event: &metrics.Event{},
   103  	})
   104  	err := morqa.sendMetrics("")
   105  
   106  	assert.EqualError(t, err, fmt.Sprintf(
   107  		"server response invalid: 400 Bad Request (%s/batch). Possible error: invalid payload given",
   108  		server.URL,
   109  	))
   110  }
   111  
   112  func TestMORQATransport_SendEvent_HandlesValidationErrors(t *testing.T) {
   113  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   114  		w.WriteHeader(http.StatusUnprocessableEntity)
   115  		_, _ = w.Write([]byte(`{
   116  			"message": "validation problems",
   117  			"errors": {
   118  				"field": [ {"code": "required", "message": "Field is required"} ]
   119  			}
   120  		}`))
   121  	}))
   122  
   123  	morqa := NewMorqaClient(httpClient, server.URL, signerFactory)
   124  	morqa.addMetric(metric{
   125  		event: &metrics.Event{},
   126  	})
   127  	err := morqa.sendMetrics("")
   128  
   129  	assert.EqualError(t, err, fmt.Sprintf(
   130  		"server response invalid: 422 Unprocessable Entity (%s/batch). Possible error: validation problems",
   131  		server.URL,
   132  	))
   133  }
   134  
   135  func TestMORQA_ProposalQuality(t *testing.T) {
   136  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   137  		_, _ = w.Write([]byte(`[{
   138  			"proposalId": { "providerId": "0x61400b27616f3ce15a86e4cd12c27c7a4d1c545c", "serviceType": "openvpn" },
   139  			"quality": 2
   140  		}, {
   141  			"proposalId": { "providerId": "0xb724ba4f646babdebaaad1d1aea6b26df568e8f6", "serviceType": "openvpn" },
   142  			"quality": 1
   143  		}, {
   144  			"proposalId": { "providerId": "0x093285d0a05ad5d9a05e0dae1eb69e7437fa02c6", "serviceType": "openvpn" },
   145  			"quality": 0
   146  		}]`))
   147  	}))
   148  
   149  	morqa := NewMorqaClient(httpClient, server.URL, signerFactory)
   150  	proposalMetrics := morqa.ProposalsQuality()
   151  
   152  	assert.Equal(t,
   153  		[]ProposalQuality{
   154  			{
   155  				ProposalID: ProposalID{ProviderID: "0x61400b27616f3ce15a86e4cd12c27c7a4d1c545c", ServiceType: "openvpn"},
   156  				Quality:    2,
   157  			},
   158  			{
   159  				ProposalID: ProposalID{ProviderID: "0xb724ba4f646babdebaaad1d1aea6b26df568e8f6", ServiceType: "openvpn"},
   160  				Quality:    1,
   161  			},
   162  			{
   163  				ProposalID: ProposalID{ProviderID: "0x093285d0a05ad5d9a05e0dae1eb69e7437fa02c6", ServiceType: "openvpn"},
   164  				Quality:    0,
   165  			},
   166  		},
   167  		proposalMetrics,
   168  	)
   169  }
   170  
   171  type mockLocationResolver struct{}
   172  
   173  func (mlr *mockLocationResolver) GetOrigin() locationstate.Location {
   174  	return locationstate.Location{}
   175  }