Fix tests

This commit is contained in:
Eugene Burmakin 2025-05-04 00:16:02 +02:00
parent ac5d14f4a7
commit e6fddddc01
5 changed files with 168 additions and 140 deletions

View file

@ -5,10 +5,9 @@ class Points::Create
def initialize(user, params) def initialize(user, params)
@user = user @user = user
@params = params @params = params.to_h
end end
# rubocop:disable Metrics/MethodLength
def call def call
data = Points::Params.new(params, user.id).call data = Points::Params.new(params, user.id).call
@ -19,7 +18,7 @@ class Points::Create
result = Point.upsert_all( result = Point.upsert_all(
location_batch, location_batch,
unique_by: %i[lonlat timestamp user_id], unique_by: %i[lonlat timestamp user_id],
returning: %i[id lonlat timestamp] returning: Arel.sql('id, timestamp, ST_X(lonlat::geometry) AS longitude, ST_Y(lonlat::geometry) AS latitude')
) )
# rubocop:enable Rails/SkipsModelValidations # rubocop:enable Rails/SkipsModelValidations
@ -28,5 +27,4 @@ class Points::Create
created_points created_points
end end
# rubocop:enable Metrics/MethodLength
end end

View file

@ -9,6 +9,16 @@ RSpec.describe 'Api::V1::Points', type: :request do
create(:point, user:, timestamp: 1.day.ago + i.minutes) create(:point, user:, timestamp: 1.day.ago + i.minutes)
end end
end end
let(:point_params) do
{
locations: [
{
geometry: { type: 'Point', coordinates: [1.0, 1.0] },
properties: { timestamp: '2025-01-17T21:03:01Z' }
}
]
}
end
describe 'GET /index' do describe 'GET /index' do
context 'when regular version of points is requested' do context 'when regular version of points is requested' do
@ -122,9 +132,16 @@ RSpec.describe 'Api::V1::Points', type: :request do
describe 'POST /create' do describe 'POST /create' do
it 'returns a successful response' do it 'returns a successful response' do
post "/api/v1/points?api_key=#{user.api_key}", params: { point: { latitude: 1.0, longitude: 1.0 } } post "/api/v1/points?api_key=#{user.api_key}", params: point_params
expect(response).to have_http_status(:success) expect(response).to have_http_status(:ok)
json_response = JSON.parse(response.body)['data']
expect(json_response.size).to be_positive
expect(json_response.first['latitude']).to eq(1.0)
expect(json_response.first['longitude']).to eq(1.0)
expect(json_response.first['timestamp']).to be_an_instance_of(Integer)
end end
context 'when user is inactive' do context 'when user is inactive' do
@ -133,7 +150,7 @@ RSpec.describe 'Api::V1::Points', type: :request do
end end
it 'returns an unauthorized response' do it 'returns an unauthorized response' do
post "/api/v1/points?api_key=#{user.api_key}", params: { point: { latitude: 1.0, longitude: 1.0 } } post "/api/v1/points?api_key=#{user.api_key}", params: point_params
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end

View file

@ -50,7 +50,7 @@ RSpec.describe Points::Create do
.with( .with(
processed_data, processed_data,
unique_by: %i[lonlat timestamp user_id], unique_by: %i[lonlat timestamp user_id],
returning: %i[id lonlat timestamp] returning: Arel.sql('id, timestamp, ST_X(lonlat::geometry) AS longitude, ST_Y(lonlat::geometry) AS latitude')
) )
.and_return(upsert_result) .and_return(upsert_result)
@ -205,7 +205,7 @@ RSpec.describe Points::Create do
.with( .with(
all_processed_data, all_processed_data,
unique_by: %i[lonlat timestamp user_id], unique_by: %i[lonlat timestamp user_id],
returning: %i[id lonlat timestamp] returning: Arel.sql('id, timestamp, ST_X(lonlat::geometry) AS longitude, ST_Y(lonlat::geometry) AS latitude')
) )
.and_return(expected_results) .and_return(expected_results)
end end

View file

@ -100,76 +100,84 @@ describe 'Points API', type: :request do
parameter name: :locations, in: :body, schema: { parameter name: :locations, in: :body, schema: {
type: :object, type: :object,
properties: { properties: {
type: { type: :string }, locations: {
geometry: { type: :array,
type: :object, items: {
properties: { type: :object,
type: { properties: {
type: :string, type: { type: :string },
example: 'Point', geometry: {
description: 'the geometry type, always Point' type: :object,
}, properties: {
coordinates: { type: {
type: :array, type: :string,
items: { example: 'Point',
type: :number, description: 'the geometry type, always Point'
example: [-122.40530871, 37.74430413], },
description: 'the coordinates of the point, longitude and latitude' coordinates: {
type: :array,
items: {
type: :number,
example: [-122.40530871, 37.74430413],
description: 'the coordinates of the point, longitude and latitude'
}
}
}
},
properties: {
type: :object,
properties: {
timestamp: {
type: :string,
example: '2025-01-17T21:03:01Z',
description: 'the timestamp of the point'
},
horizontal_accuracy: {
type: :number,
example: 5,
description: 'the horizontal accuracy of the point in meters'
},
vertical_accuracy: {
type: :number,
example: -1,
description: 'the vertical accuracy of the point in meters'
},
altitude: {
type: :number,
example: 0,
description: 'the altitude of the point in meters'
},
speed: {
type: :number,
example: 92.088,
description: 'the speed of the point in meters per second'
},
speed_accuracy: {
type: :number,
example: 0,
description: 'the speed accuracy of the point in meters per second'
},
course_accuracy: {
type: :number,
example: 0,
description: 'the course accuracy of the point in degrees'
},
track_id: {
type: :string,
example: '799F32F5-89BB-45FB-A639-098B1B95B09F',
description: 'the track id of the point set by the device'
},
device_id: {
type: :string,
example: '8D5D4197-245B-4619-A88B-2049100ADE46',
description: 'the device id of the point set by the device'
}
}
} }
} },
required: %w[geometry properties]
} }
}, }
properties: {
type: :object,
properties: {
timestamp: {
type: :string,
example: '2025-01-17T21:03:01Z',
description: 'the timestamp of the point'
},
horizontal_accuracy: {
type: :number,
example: 5,
description: 'the horizontal accuracy of the point in meters'
},
vertical_accuracy: {
type: :number,
example: -1,
description: 'the vertical accuracy of the point in meters'
},
altitude: {
type: :number,
example: 0,
description: 'the altitude of the point in meters'
},
speed: {
type: :number,
example: 92.088,
description: 'the speed of the point in meters per second'
},
speed_accuracy: {
type: :number,
example: 0,
description: 'the speed accuracy of the point in meters per second'
},
course_accuracy: {
type: :number,
example: 0,
description: 'the course accuracy of the point in degrees'
},
track_id: {
type: :string,
example: '799F32F5-89BB-45FB-A639-098B1B95B09F',
description: 'the track id of the point set by the device'
},
device_id: {
type: :string,
example: '8D5D4197-245B-4619-A88B-2049100ADE46',
description: 'the device id of the point set by the device'
}
}
},
required: %w[geometry properties]
} }
} }
@ -179,8 +187,7 @@ describe 'Points API', type: :request do
let(:file_path) { 'spec/fixtures/files/points/geojson_example.json' } let(:file_path) { 'spec/fixtures/files/points/geojson_example.json' }
let(:file) { File.open(file_path) } let(:file) { File.open(file_path) }
let(:json) { JSON.parse(file.read) } let(:json) { JSON.parse(file.read) }
let(:params) { json } let(:locations) { json }
let(:locations) { params['locations'] }
let(:api_key) { create(:user).api_key } let(:api_key) { create(:user).api_key }
run_test! run_test!
@ -190,8 +197,7 @@ describe 'Points API', type: :request do
let(:file_path) { 'spec/fixtures/files/points/geojson_example.json' } let(:file_path) { 'spec/fixtures/files/points/geojson_example.json' }
let(:file) { File.open(file_path) } let(:file) { File.open(file_path) }
let(:json) { JSON.parse(file.read) } let(:json) { JSON.parse(file.read) }
let(:params) { json } let(:locations) { json }
let(:locations) { params['locations'] }
let(:api_key) { 'invalid_api_key' } let(:api_key) { 'invalid_api_key' }
run_test! run_test!

View file

@ -847,65 +847,72 @@ paths:
schema: schema:
type: object type: object
properties: properties:
type: locations:
type: string type: array
geometry: items:
type: object type: object
properties: properties:
type: type:
type: string type: string
example: Point geometry:
description: the geometry type, always Point type: object
coordinates: properties:
type: array type:
items: type: string
type: number example: Point
example: description: the geometry type, always Point
- -122.40530871 coordinates:
- 37.74430413 type: array
description: the coordinates of the point, longitude and latitude items:
properties: type: number
type: object example:
properties: - -122.40530871
timestamp: - 37.74430413
type: string description: the coordinates of the point, longitude
example: '2025-01-17T21:03:01Z' and latitude
description: the timestamp of the point properties:
horizontal_accuracy: type: object
type: number properties:
example: 5 timestamp:
description: the horizontal accuracy of the point in meters type: string
vertical_accuracy: example: '2025-01-17T21:03:01Z'
type: number description: the timestamp of the point
example: -1 horizontal_accuracy:
description: the vertical accuracy of the point in meters type: number
altitude: example: 5
type: number description: the horizontal accuracy of the point in meters
example: 0 vertical_accuracy:
description: the altitude of the point in meters type: number
speed: example: -1
type: number description: the vertical accuracy of the point in meters
example: 92.088 altitude:
description: the speed of the point in meters per second type: number
speed_accuracy: example: 0
type: number description: the altitude of the point in meters
example: 0 speed:
description: the speed accuracy of the point in meters per second type: number
course_accuracy: example: 92.088
type: number description: the speed of the point in meters per second
example: 0 speed_accuracy:
description: the course accuracy of the point in degrees type: number
track_id: example: 0
type: string description: the speed accuracy of the point in meters
example: 799F32F5-89BB-45FB-A639-098B1B95B09F per second
description: the track id of the point set by the device course_accuracy:
device_id: type: number
type: string example: 0
example: 8D5D4197-245B-4619-A88B-2049100ADE46 description: the course accuracy of the point in degrees
description: the device id of the point set by the device track_id:
required: type: string
- geometry example: 799F32F5-89BB-45FB-A639-098B1B95B09F
- properties description: the track id of the point set by the device
device_id:
type: string
example: 8D5D4197-245B-4619-A88B-2049100ADE46
description: the device id of the point set by the device
required:
- geometry
- properties
examples: examples:
'0': '0':
summary: Creates a batch of points summary: Creates a batch of points