<!-- 
RSS generated by JIRA (1001.0.0-SNAPSHOT#100246-sha1:7a5c50119eb0633d306e14180817ddef5e80c75d) at Thu Feb 08 23:07:36 UTC 2024

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary add field=key&field=summary to the URL of your request.
-->
<rss version="0.92" >
<channel>
    <title>FOLIO Jira</title>
    <link>https://folio-org.atlassian.net</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>1001.0.0-SNAPSHOT</version>
        <build-number>100246</build-number>
        <build-date>07-02-2024</build-date>
    </build-info>

<item>
            <title>[FOLIO-685] explore auto-generation of fakes (mocks) for module testing</title>
                <link>https://folio-org.atlassian.net/browse/FOLIO-685</link>
                <project id="10290" key="FOLIO">FOLIO</project>
                    <description>&lt;p&gt;This came up during the core meeting today. In principle we should be able to generate mock (fake) services from RAML/Schema specs (which contain example data). We suspect this is not going to be good enough for testing more specialized functionality but it might be a good starting point. So the tool could generate some boilerplate mock/fake code that the developer than could modify to fit the needs of the test.&lt;/p&gt;</description>
                <environment></environment>
        <key id="80237">FOLIO-685</key>
            <summary>explore auto-generation of fakes (mocks) for module testing</summary>
                <type id="10003" iconUrl="https://folio-org.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10318?size=medium">Task</type>
                                            <priority id="10002" iconUrl="https://dev.folio.org/assets/jira-priority/jira-p3.svg">P3</priority>
                        <status id="6" iconUrl="https://folio-org.atlassian.net/images/icons/statuses/closed.png" description="The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.">Closed</status>
                    <statusCategory id="3" key="done" colorName="green"/>
                                    <resolution id="10000">Won&apos;t Do</resolution>
                                                        <assignee accountid="712020:32bb56ac-50e7-4787-b4af-ed3089d9401c">shale99</assignee>
                                                                <reporter accountid="557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d">Jakub Skoczen</reporter>
                                    <labels>
                            <label>for-next-sprint</label>
                    </labels>
                <created>Tue, 20 Jun 2017 13:54:53 +0000</created>
                <updated>Thu, 2 Sep 2021 12:31:08 +0000</updated>
                            <resolved>Thu, 2 Sep 2021 12:31:08 +0000</resolved>
                                                                        <due></due>
                            <votes>0</votes>
                                    <watches>4</watches>
                                                                <comments>
                                                            <comment id="188582" author="712020:32bb56ac-50e7-4787-b4af-ed3089d9401c" created="Sun, 2 Jul 2017 15:05:55 +0000"  >&lt;p&gt;started looking into this initially trying to use Google&apos;s Guice framework for DI. Decided to go a simpler route for now. Prototyped locally:&lt;/p&gt;

&lt;p&gt;1. RMB has its own http client which wraps vertx&apos;s http client - adding caching, build cql functionality, etc...&lt;br/&gt;
2. i created a mock http as well - it implements the same interface as the actual RMB http client with the exception that the Responses returned per endpoint are indicated in a mock_content.json found in the classpath. this means that when you make a call to the http client - if you are in mock mode (sys property) - then the Response returned will be created from the entry in the content json matching the endpoint + method&lt;/p&gt;

&lt;p&gt;example of the mock_content.json&lt;/p&gt;


&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;

{
  &lt;span class=&quot;code-quote&quot;&gt;&quot;mocks&quot;&lt;/span&gt;: [
    {
      &lt;span class=&quot;code-quote&quot;&gt;&quot;description&quot;&lt;/span&gt; : &lt;span class=&quot;code-quote&quot;&gt;&quot;url -&amp;gt; when &lt;span class=&quot;code-keyword&quot;&gt;this&lt;/span&gt; url is called with the method [get / put  / etc...] than &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; the request requires input data &quot;&lt;/span&gt;,
      &lt;span class=&quot;code-quote&quot;&gt;&quot;url&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;/users?query=username=joe&quot;&lt;/span&gt;,
      &lt;span class=&quot;code-quote&quot;&gt;&quot;method&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;get&quot;&lt;/span&gt;,
      &lt;span class=&quot;code-quote&quot;&gt;&quot;status&quot;&lt;/span&gt;: 200,
      &lt;span class=&quot;code-quote&quot;&gt;&quot;receivedData&quot;&lt;/span&gt;: {&lt;span class=&quot;code-quote&quot;&gt;&quot;id&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;1&quot;&lt;/span&gt;,&lt;span class=&quot;code-quote&quot;&gt;&quot;a31&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;1&quot;&lt;/span&gt;},
      &lt;span class=&quot;code-quote&quot;&gt;&quot;receivedPath&quot;&lt;/span&gt;: &quot;&quot;,
      &lt;span class=&quot;code-quote&quot;&gt;&quot;sendData&quot;&lt;/span&gt; : {},
      &lt;span class=&quot;code-quote&quot;&gt;&quot;headers&quot;&lt;/span&gt; : [
        {&lt;span class=&quot;code-quote&quot;&gt;&quot;name&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;x-okapi-token&quot;&lt;/span&gt;, &lt;span class=&quot;code-quote&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;12345&quot;&lt;/span&gt;},
        {&lt;span class=&quot;code-quote&quot;&gt;&quot;name&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;x-okapi-tenant&quot;&lt;/span&gt;, &lt;span class=&quot;code-quote&quot;&gt;&quot;value&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;eeee&quot;&lt;/span&gt;}
      ]
    },
    {
      &lt;span class=&quot;code-quote&quot;&gt;&quot;url&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;auth_test2&quot;&lt;/span&gt;,
      &lt;span class=&quot;code-quote&quot;&gt;&quot;method&quot;&lt;/span&gt;: &lt;span class=&quot;code-quote&quot;&gt;&quot;get&quot;&lt;/span&gt;,
      &lt;span class=&quot;code-quote&quot;&gt;&quot;status&quot;&lt;/span&gt;: 200,
      &lt;span class=&quot;code-quote&quot;&gt;&quot;receivedData&quot;&lt;/span&gt; : {},
      &lt;span class=&quot;code-quote&quot;&gt;&quot;receivedPath&quot;&lt;/span&gt;: &quot;&quot;,
      &lt;span class=&quot;code-quote&quot;&gt;&quot;sendData&quot;&lt;/span&gt; : {}
    }
  ]
}
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;</comment>
                                                            <comment id="188586" author="712020:32bb56ac-50e7-4787-b4af-ed3089d9401c" created="Mon, 3 Jul 2017 07:36:07 +0000"  >&lt;p&gt;a bit more info - the mock http service will also indicate which urls you are attempting to access and will return a mock error if you have not indicated what to return for a specific url. &lt;/p&gt;

&lt;p&gt;For example - the below is the error output when calling &lt;tt&gt;/bl-users?query=username=joe&lt;/tt&gt;  without having an entry in the &lt;tt&gt;mock_content.json&lt;/tt&gt; for the  &lt;tt&gt;/groups&lt;/tt&gt;  url. Note that this runs the actual mod-users-bl service - only replaces the http client with the mock http client (due to the sys property indicated at verticle startup) - the URLs in mod-users-bl (as with other biz modules) are auto generated from the json returned from the /users (or other) endpoint - so when mocking json responses - you need to be aware (or at least run the mock once to see) of which urls need to be mocked&lt;/p&gt;


&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;
[Mon Jul 03 10:26:52 IDT 2017] org.folio.&lt;span class=&quot;code-keyword&quot;&gt;rest&lt;/span&gt;.tools.client.test.HttpClientMock2 INFO MOCKING URL: /users?query=username=joe&amp;amp;offset=0&amp;amp;limit=10 
[Mon Jul 03 10:26:55 IDT 2017] org.folio.&lt;span class=&quot;code-keyword&quot;&gt;rest&lt;/span&gt;.tools.client.test.HttpClientMock2 INFO MOCKING URL: /groups?query=id==4bb563d9-3f9d-4e1e-8d1d-04e75666d68f 
[Mon Jul 03 10:26:57 IDT 2017] org.folio.&lt;span class=&quot;code-keyword&quot;&gt;rest&lt;/span&gt;.tools.client.test.HttpClientMock2 INFO MOCKING URL: /perms/users?query=username==jhandey 
[Mon Jul 03 10:27:01 IDT 2017] org.folio.&lt;span class=&quot;code-keyword&quot;&gt;rest&lt;/span&gt;.impl.BlUsersAPI SEVERE {
  &lt;span class=&quot;code-quote&quot;&gt;&quot;endpoint&quot;&lt;/span&gt; : &lt;span class=&quot;code-quote&quot;&gt;&quot;/groups?query=id==4bb563d9-3f9d-4e1e-8d1d-04e75666d68f&quot;&lt;/span&gt;,
  &lt;span class=&quot;code-quote&quot;&gt;&quot;statusCode&quot;&lt;/span&gt; : 0,
  &lt;span class=&quot;code-quote&quot;&gt;&quot;errorMessage&quot;&lt;/span&gt; : &lt;span class=&quot;code-quote&quot;&gt;&quot;mocked error&quot;&lt;/span&gt;
} 
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;</comment>
                                                            <comment id="188588" author="712020:32bb56ac-50e7-4787-b4af-ed3089d9401c" created="Mon, 3 Jul 2017 08:12:42 +0000"  >&lt;p&gt;sys property to indicate mock mode: &lt;tt&gt;-Dmock.httpclient&lt;/tt&gt;&lt;br/&gt;
factory to use to retrieve rmb http client (additional overloaded methods exist):&lt;br/&gt;
&lt;tt&gt;HttpClientInterface client = HttpClientFactory.getHttpClient(okapiURL, tenant);&lt;/tt&gt;&lt;/p&gt;

&lt;p&gt;note that if the json passed in is large - you can place it in a separate file and then reference it relatively via the &lt;tt&gt;&quot;receivedPath&quot;: &quot;&quot;,&lt;/tt&gt; field in the mock_content.json&lt;/p&gt;

&lt;p&gt;the headers section allows you to indicate which headers / values the endpoint will return (simulate)&lt;/p&gt;</comment>
                                                            <comment id="188592" author="712020:32bb56ac-50e7-4787-b4af-ed3089d9401c" created="Mon, 3 Jul 2017 11:49:43 +0000"  >&lt;p&gt;unit test example using mocks:&lt;/p&gt;

&lt;p&gt;start verticle in mock mode:&lt;/p&gt;

&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;
    DeploymentOptions options = &lt;span class=&quot;code-keyword&quot;&gt;new&lt;/span&gt; DeploymentOptions().setConfig(&lt;span class=&quot;code-keyword&quot;&gt;new&lt;/span&gt; JsonObject().put(&lt;span class=&quot;code-quote&quot;&gt;&quot;http.port&quot;&lt;/span&gt;,
      port).put(HttpClientMock2.MOCK_MODE, &lt;span class=&quot;code-quote&quot;&gt;&quot;&lt;span class=&quot;code-keyword&quot;&gt;true&lt;/span&gt;&quot;&lt;/span&gt;));
    vertx.deployVerticle(RestVerticle.&lt;span class=&quot;code-keyword&quot;&gt;class.&lt;/span&gt;getName(), options, context.asyncAssertSuccess(id -&amp;gt; {
      async.complete();
    }));
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;check response returned from veritcle endpoint - internally, the endpoint will replace outgoing calls to other modules with content from the mock_content.json&lt;/p&gt;

&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;

      CompletableFuture&amp;lt;Response&amp;gt; response = httpClient.request(&lt;span class=&quot;code-quote&quot;&gt;&quot;/bl-users?include=perms&quot;&lt;/span&gt;);
      response.whenComplete( (resp, ex) -&amp;gt; {
      &lt;span class=&quot;code-keyword&quot;&gt;try&lt;/span&gt; {
        assertEquals(200, resp.getCode());
        &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt;(resp.getError() != &lt;span class=&quot;code-keyword&quot;&gt;null&lt;/span&gt;){
          &lt;span class=&quot;code-object&quot;&gt;System&lt;/span&gt;.out.println(resp.getError().encode());
        }
        async.complete();
      } &lt;span class=&quot;code-keyword&quot;&gt;catch&lt;/span&gt; (Throwable e) {
        context.fail(e.getMessage());
      }
      });
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;</comment>
                                                            <comment id="188595" author="712020:32bb56ac-50e7-4787-b4af-ed3089d9401c" created="Sun, 16 Jul 2017 09:57:06 +0000"  >&lt;p&gt;summary:&lt;br/&gt;
RMB v13.0.0 supports mocking http requests when using rmb&apos;s http client (as explained in the issue)&lt;br/&gt;
The rmb http client is a wrapper around the vertx http client - it adds caching, building cqls, complete-able future , chaining requests support , etc...&lt;/p&gt;

&lt;p&gt;using the sys property / vertx config property - you can indicate to the verticle which mode you are running in (regular or mock) - in case of mock mode - you create a json with an entry per url you are calling from within your module and indicate (in the json) what data , status code , and headers should be returned when that url is called - in mock mode - the request will not be sent out but the response will be constructed from the json entries&lt;/p&gt;</comment>
                                                            <comment id="188598" author="712020:32bb56ac-50e7-4787-b4af-ed3089d9401c" created="Mon, 17 Jul 2017 10:45:59 +0000"  >&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=5c38e8d616ac1e4f7cbc660a&quot; class=&quot;user-hover&quot; rel=&quot;5c38e8d616ac1e4f7cbc660a&quot; data-account-id=&quot;5c38e8d616ac1e4f7cbc660a&quot; accountid=&quot;5c38e8d616ac1e4f7cbc660a&quot; rel=&quot;noreferrer&quot;&gt;Kurt Nordstrom&lt;/a&gt; , &lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=63e2a2771b13d42998e4e706&quot; class=&quot;user-hover&quot; rel=&quot;63e2a2771b13d42998e4e706&quot; data-account-id=&quot;63e2a2771b13d42998e4e706&quot; accountid=&quot;63e2a2771b13d42998e4e706&quot; rel=&quot;noreferrer&quot;&gt;Marc Johnson&lt;/a&gt; , &lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=557058%3Ab8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; class=&quot;user-hover&quot; rel=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; data-account-id=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; accountid=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; rel=&quot;noreferrer&quot;&gt;Jakub Skoczen&lt;/a&gt; - any comments on this, different implementation ideas?&lt;/p&gt;</comment>
                                                            <comment id="188599" author="63e2a2771b13d42998e4e706" created="Tue, 18 Jul 2017 09:42:54 +0000"  >&lt;p&gt;&lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=712020%3A32bb56ac-50e7-4787-b4af-ed3089d9401c&quot; class=&quot;user-hover&quot; rel=&quot;712020:32bb56ac-50e7-4787-b4af-ed3089d9401c&quot; data-account-id=&quot;712020:32bb56ac-50e7-4787-b4af-ed3089d9401c&quot; accountid=&quot;712020:32bb56ac-50e7-4787-b4af-ed3089d9401c&quot; rel=&quot;noreferrer&quot;&gt;shale99&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If my understanding of this approach is sensible, the goal is to replace the HTTP client (via configuration) within a RAML-module-builder based module in order to not make requests to other interface implementations.&lt;/p&gt;

&lt;p&gt;At the moment, it appears the mock will respond to any URL defined in it&apos;s content configuration. In the future, do you envisage that the mock will be schema / RAML aware?&lt;/p&gt;

&lt;p&gt;The approach that the inventory and circulation modules have taken up until now is different, they use external fake implementations (based upon conventions at the moment) running externally to the module being tested.&lt;/p&gt;</comment>
                                                            <comment id="188600" author="712020:32bb56ac-50e7-4787-b4af-ed3089d9401c" created="Tue, 18 Jul 2017 10:10:00 +0000"  >&lt;p&gt;right, the idea behind the rmb mocks is that, based on a config you can indicate you are running in mock mode.&lt;br/&gt;
when that is indicated the rmb http client is replaced with a mock rmb http client which reads from a json file entries.&lt;br/&gt;
the entries in the json file are external urls used internally by the exposed mod-user-bl apis - so for example, if mod-users-bl login is called - this is actually made up of multiple calls internally to a number of external modules - to /users , /authn/login, etc...&lt;br/&gt;
so in the json config file you would indicate what should be returned for each of those internal urls called by the mod-users-bl login - so there would be a /users entry , a /authn/login entry, etc... in the json with the static response to return for each url along with headers and the response code.&lt;br/&gt;
so when unit testing , you can call the mod-users-bl apis and the apis needed internally by each mod-users-bl endpoint to fulfill each api is actually a lookup into the json config file. this allows you to create a really wide set of tests really quickly (just by adding entries into the config json) - as you can add errors, corrupt data, different status codes, special chars, etc...  &lt;/p&gt;</comment>
                    </comments>
                    <attachments>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                <customfield id="customfield_10000" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummarycf">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_10019" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>0|hzxpl3:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_10020" key="com.pyxis.greenhopper.jira:gh-sprint">
                        <customfieldname>Sprint</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        <customfield id="customfield_10024" key="com.atlassian.jira.ext.charting:firstresponsedate">
                        <customfieldname>[CHART] Date of First Response</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>Sun, 2 Jul 2017 15:05:55 +0000</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10025" key="com.atlassian.jira.ext.charting:timeinstatus">
                        <customfieldname>[CHART] Time in Status</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                    </customfields>
    </item>
</channel>
</rss>