Amadeus SDK integration to Kotlin Compose crashed the app - kotlin

I was following Amadeus SDK integration to my Composable app, but I am having the issues while running it. For example, if I run it in a Composable function it suddenly shuts down the app and there is no provided message of the error. During the debugging process it passes all the way to var amadeus variable, then shows the amadeus value, which is shown below and crashes. Maybe I am calling in the wrong way or could be problem of the passed context variable to Amadeus.Builder() that I am passing to it?
Code snippet
#Composable
fun HotelScreen(context: Context) {
val job = SupervisorJob()
val scope = CoroutineScope(Dispatchers.Main + job)
var amadeus = Amadeus.Builder(context)
.setClientId("sBil...")
.setClientSecret("Zwgt...")
.build()
...
}
Snippet of amadeus variable error

Related

How to test subscribe call of Observable using Mockk?

I have a function in my ViewModel in which I subscribe to some updates, I want to write a test that will check that after the subscribe is triggered, the specific function is called from the subscribe.
Here is how the function looks:
fun subscribeToTablesUpdates() {
dataManager.getTablesList()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { tablesList ->
updateTablesState(tablesList)
}
}
And this is the test that I wrote:
#Test
fun subscribeToTablesListTest() {
val mockedTablesList = mockk<List<Table>()
every {
viewModel.dataManager.getTablesList()
} returns Observable.just(mockedTablesList)
viewModel.subscribeToTablesUpdates()
verify {
viewModel.updateTablesState(mockedTablesList)
}
}
The issue is that I receive assertion exception without any another info and I don't know how to fix that.
Edit 1: subscribeToTableUpdates() is calling from the init block of ViewModel.
So basically the test itself was done right, but there were linking issue. Since the function of the VM was called from the init block the subscription happened only once, and that created a situation when at the time when I mocked the data service, the observer was already subscribed to the other service. Since the init block is called only once, there is no way to change the implementation of the data service to that observer.
After all this investigation the one thing which I successfully forgot came to my mind again: extract every external dependencies to constructors, so further you could substitute it for the test without any problems like this.

callback function called from coroutine does not run with KotlinJS

I am trying to write a Kotlin function that executes a HTTP request, then gives the result back to JavaScript.
Because with the IR compiler I cannot use a suspended function from JavaScript, I am trying to use a callback instead.
However, the callback is never executed when called from a coroutine.
Here's a small sample of what I am doing:
private val _httpClient = HttpClient(JsClient()) {
install(ContentNegotiation) { json() }
defaultRequest { url(settings.baseUrl) }
}
fun requestJwtVcJsonCredential(
request: JSJwtVcJsonVerifiableCredentialRequest,
callback: (JSDeferredJsonCredentialResponse?, JSJwtVcJsonVerifiableCredentialResponse?, Any?) -> Unit
) {
CoroutineScope(_httpClient.coroutineContext).launch {
// call suspend function
val response = requestCredential(convert(request))
// this never runs, even though the coroutine does run successfully
println("Coroutine received: $response")
callback(response.first, response.second, response.third)
}
}
I've noticed this question had a similar problem in Android, but the suggested fix does not apply to JavaScript... specifically, using a Channel does not help in my case because I don't have a coroutine to receive from, and trying to start a new coroutine to receive from the channel, then calling the callback from that coroutine, also doesn't work (the root problem seems to be that I cannot call a callback function from any coroutine).
What's the best way to solve this problem? Assume the function I need to call is a suspend function (the HTTP Client function) and I cannot change that, but I could change everything around it so that it works from a non-suspend function (as that's a limitation of Kotlin JS).
The root problem was that the suspend function was actually failing, but there seems to be no default exception handler so the Exception was not logged anywhere, causing the function to fail silently, making it look like the callback was being called but not executing.
However, I think it's worth it mentioning that KotlinJS supports Promise<T>, so the better way to expose a suspend function to JS is to actually write an "adapter" function that returns a Promise instead.
There is a promise extension function on CouroutineScope which can be used for this.
So, for example, if you've got a Kotlin function like this:
suspend fun makeRequest(request: Request): Response
To expose it in JavaScript you can have an adapter function like this:
#JsExport
fun makeRequestJS(request: Request): Promise<Response> {
// KTor's HttpClient itself is a CoroutineScope
return _httpClient.promise { makeRequest(request) }
}
This avoids the need to introduce a callback function.

How to test with Response.OnCompleted delegate in a finally block

I have the following netcore 2.2 controller method that I am trying to write an xUnit integration test for:
private readonly ISoapSvc _soapSvc;
private readonly IRepositorySvc _repositorySvc;
public SnowConnectorController(ISoapSvc soapSvc, IRepositorySvc repositorySvc)
{
_soapSvc = soapSvc;
_repositorySvc = repositorySvc;
}
[Route("accept")]
[HttpPost]
[Produces("text/xml")]
public async Task<IActionResult> Accept([FromBody] XDocument soapRequest)
{
try
{
var response = new CreateRes
{
Body = new Body
{
Response = new Response
{
Status = "Accepted"
}
}
};
return Ok(response);
}
finally
{
// After the first API call completes
Response.OnCompleted(async () =>
{
// Run the close method
await Close(soapRequest);
});
}
}
The catch block runs and does the things it needs to, then the finally block runs and does things it needs to do after the request in the catch finishes per design.
Close has been both a private method . It started as a public controller method but I don't need to expose it for function so moved it to private method status.
Here's an integration test I started with the intention of just testing the try portion of the code:
[Fact]
public async Task AlwaysReturnAcceptedResponse()
{
// Arrange------
// Build mocks so that we can inject them in our system under tests constructor
var mockSoapSvc = new Mock<ISoapSvc>();
var mockRepositorySvc = new Mock<IRepositorySvc>();
// Build system under test(sut)
var sut = new SnowConnectorController(mockSoapSvc.Object, mockRepositorySvc.Object);
var mockRequest = XDocument.Load("..\\..\\..\\mockRequest.xml");
// Act------
// Form and send test request to test system
var actualResult = await sut.Accept(mockRequest);
var actualValue = actualResult.GetType().GetProperty("Value").GetValue(actualResult);
// Assert------
// The returned object from the method call should be of type CreateRes
Assert.IsType<CreateRes>(actualValue);
}
I am super new to testing... I've been writing the test and feeling my way through the problem. I started by entering the controller method not really knowing where it would go. The test works through the try method, and then an exception is thrown once it hits the delegate in the finally block.
It looks like my test will have to run through to the results of the finally block unless there is a way to tell it to stop with the catch blocks execution?
That's fine, i'm learning, but the problem with that approach for me now is that the HttpResponse's Response.OnCompleted delegate in the finally block returns null when my test is running and I haven't been successful at figuring out what I can do to not make it null - because it is null, it throws this when my unit test is executing -
System.NullReferenceException: 'Object reference not set to an instance of an object.'
*One thought that occurred was that if I was to make the private Close method a public controller method, and then make the Accept method not have the finally block, I could create a third controller method that does the try finally action by running the two controller methods and then just test the individual controller methods that are strung together with the third. However, it doesn't feel right because I would be exposing methods just for the sake of unit testing and I don't need Close to be exposed.
If the above idea is not the right approach, I am wondering what is, and if I just need to test through end to end, how I would get over the null httpresponse?
Any ideas would be appreciated. Thank you, SO community!
EDIT - Updated Test that works after the accepted answer was implemented. Thanks!
[Fact]
public async Task AlwaysReturnAcceptedResponse()
{
// Arrange------
// Build mocks so that we can inject them in our system under tests constructor
var mockSoapSvc = new Mock<ISoapSvc>();
var mockRepositorySvc = new Mock<IRepositorySvc>();
// Build system under test(sut)
var sut = new SnowConnectorController(mockSoapSvc.Object, mockRepositorySvc.Object)
{
// Supply mocked ControllerContext and HttpContext so that finally block doesnt fail test
ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext()
}
};
var mockRequest = XDocument.Load("..\\..\\..\\mockRequest.xml");
// Act------
// Form and send test request to test system
var actualResult = await sut.Accept(mockRequest);
var actualValue = actualResult.GetType().GetProperty("Value").GetValue(actualResult);
// Assert------
// The returned object from the method call should be of type CreateRes
Assert.IsType<CreateRes>(actualValue);
}
Curious what you are doing in the Close method against the input parameter.
Does it have to happen after response is being sent? It might not always happen as you would expect, see here.
Regardless though, during runtime asp.net core runtime sets a lot of properties on the controller including ControllerContext, HttpContext, Request, Response etc.
But those won't be available in unit testing since there is no asp.net core runtime there.
If you really want to test this, you'll have to mock them.
Here is the ControllerBase source code.
As we can see, ControllerBase.Response simply returns ControllerBase.HttpContext.Response, and ControllerBase.HttpContext is a getter from ControllerBase.ControllerContext. This means you'll have to mock a ControllerContext (and the nested HttpContext as well as HttpResponse) and assign it to your controller in the setup phase.
Furthermore, the OnCompleted callback won't get called in unit test either. If you want to unit test that part, you'll have to trigger it manually.
Personally I think it's too much hassle beside the open bug I mentioned above.
I would suggest you move the closing logic (if it's really necessary) to a IDisposable scoped service and handle that in the Dispose instead - assuming it's not a computation heavy operation which can impact the response latency.

Kotlin-Firebase-cannot utilize the string read from database further down in the code

I have managed to read data from my firebase database but cant seem to re-use the String which has been read.
My successful read is as per below. When i check the logcat for the Log.d("Brand") it actually shows the String as expected.
brandchosenRef=FirebaseDatabase.getInstance().reference
val brandsRef = brandchosenRef.child("CarList2").orderByChild("Car").equalTo(searchable_spinner_brand.selectedItem.toString())
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for(ds in dataSnapshot.children){
Log.d("spinner brand",searchable_spinner_brand.selectedItem.toString())
val Brand = ds.child("Brand").getValue(String::class.java)
val brandselected= Brand.toString()
Log.d("Brand","$brandselected")
selectedbrand== brandselected
Log.d("selected brand",selectedbrand)
}
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d("Branderror","error on brand")
}
}
brandsRef.addListenerForSingleValueEvent(valueEventListener)
What i am trying to do is write "selectedbrand" into a separate node using the following:
val carselected = searchable_spinner_brand.selectedItem.toString()
val dealref = FirebaseDatabase.getInstance().getReference("Deal_Summary2")
val dealsummayId = dealref.push().key
val summaryArray = DealSummaryArray(dealsummayId.toString(),"manual input for testing","brand","Deal_ID",carselected,extrastext.text.toString(),otherinfo.text.toString(),Gauteng,WC,KZN,"Open")
dealref.child(dealsummayId.toString()).setValue(summaryArray).addOnCompleteListener{
}
Note, in the above i was inputting "manual input for testing" to check that my write to Firebase was working and it works as expected. if i replace that with selectedbrand, then i get the below error.
kotlin.UninitializedPropertyAccessException: lateinit property selectedbrand has not been initialized
the summary array indicated above is defined in a separate class as follows. and as seen "manual input for testing is declared as String.
class DealSummaryArray(val id:String,val brand:String,val Buyer_ID:String,val Deal_ID:String,val Car:String,val extras:String,val other_info:String,val Gauteng:String,val Western_Cape:String,val KZN:String,val Status:String) {
constructor():this("","","","","","","","","","",""){
}
}
My question simply put, it why can i not re-use the value i read from the database? even if i was not trying to re-write it to a new node i cannot seem to utilize the value outside of the firebase query.
I seem to get this problem everywhere in my activities and have to find strange work around's like write to a textview and then reference the textview. please assist.
Data is loaded from Firebase asynchronously, as it may take some time before you get a response from the server. To prevent blocking the application (which would be a bad experience for your users), your main code continues to run while the data is being loaded. And then when the data is available, Firebase calls your onDataChange method.
What this means in practice is that any code that needs the data from the database, needs to be inside the onDataChange method or be called from there. So any code that requires selectedbrand needs to be inside onDataChange or called from there (typically through a callback interface).
Also see:
How to check a certain data already exists in firestore or not, which contains example code including of the callback interface, in Java.
getContactsFromFirebase() method return an empty list, which contains a similar example for the Firebase Realtime Database.
Setting Singleton property value in Firebase Listener, which shows a way to make the code behave more synchronous, and explains shows that this may not work on various Android versions.

Unit testing WebFlux Routers with Spek

I have been using Spring's WebFlux framework with Kotlin for about a month now, and have been loving it. As I got ready to make the dive into writing production code with WebFlux and Kotlin I found myself struggling to unit test my routers in a simple, lightweight way.
Spring Test is an excellent framework, however it is heavier weight than what I was wanting, and I was looking for a test framework that was more expressive than traditional JUnit. Something in the vein of JavaScript's Mocha. Kotlin's Spek fit the bill perfectly.
What follows below is an example of how I was able to unit test a simple router using Spek.
WebFlux defines an excellent DSL using Kotlin's Type-Safe Builders for building routers. While the syntax is very succinct and readable it is not readily apparent how to assert that the router function bean it returns is configured properly as its properties are mostly inaccessible to client code.
Say we have the following router:
#Configuration
class PingRouter(private val pingHandler: PingHandler) {
#Bean
fun pingRoute() = router {
accept(MediaType.APPLICATION_JSON).nest {
GET("/ping", pingHandler::handlePing)
}
}
}
We want to assert that when a request comes in that matches the /ping route with an application/json content header the request is passed off to our handler function.
object PingRouterTest: Spek({
describe("PingRouter") {
lateinit var pingHandler: PingHandler
lateinit var pingRouter: PingRouter
beforeGroup {
pingHandler = mock()
pingRouter = PingRouter(pingHandler)
}
on("Ping route") {
/*
We need to setup a dummy ServerRequest who's path will match the path of our router,
and who's headers will match the headers expected by our router.
*/
val request: ServerRequest = mock()
val headers: ServerRequest.Headers = mock()
When calling request.pathContainer() itReturns PathContainer.parsePath("/ping")
When calling request.method() itReturns HttpMethod.GET
When calling request.headers() itReturns headers
When calling headers.accept() itReturns listOf(MediaType.APPLICATION_JSON)
/*
We call pingRouter.pingRoute() which will return a RouterFunction. We then call route()
on the RouterFunction to actually send our dummy request to the router. WebFlux returns
a Mono that wraps the reference to our PingHandler class's handler function in a
HandlerFunction instance if the request matches our router, if it does not, WebFlux will
return an empty Mono. Finally we invoke handle() on the HandlerFunction to actually call
our handler function in our PingHandler class.
*/
pingRouter.pingRoute().route(request).subscribe({ it.handle(request) })
/*
If our pingHandler.handlePing() was invoked by the HandlerFunction, we know we properly
configured our route for the request.
*/
it("Should call the handler with request") {
verify(pingHandler, times(1)).handlePing(request)
}
}
}
})