Skip to content

Commit

Permalink
tests added, readme updated
Browse files Browse the repository at this point in the history
  • Loading branch information
sf2ne committed Mar 9, 2020
1 parent ea2c0f2 commit 50246d6
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 1 deletion.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,11 @@ Now you can disable root by setting `api.root.enabled` to `false` in `/etc/horiz
- detect if a pattern is updated with service that has userInput w/o default values, and give warning
- Consider changing all creates to POST, and update (via put/patch) return codes to 200

## Changes in 2.14.0

- Issue 311: Notification Framework Agbot Case
- Fixes for Scalatest upgrade to 3.1

## Changes in 2.13.0

- Issue 312: Using only node table's lastUpdated field to filter on (updating lastUpdated in node, policy, and agreement changes)
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/com/horizon/exchangeapi/OrgsRoutes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ trait OrgsRoutes extends JacksonSupport with AuthenticationSupport {
case Success(n) =>
logger.debug(s"POST /orgs/$orgId/changes node/agbot heartbeat result: $n")
if (n > 0) {
val hitMaxRecords = (qResp.size == reqBody.maxRecords) // if they are equal then we hit maxRecords
val hitMaxRecords = (qResp.size == maxRecords) // if they are equal then we hit maxRecords
if(qResp.nonEmpty) (HttpCode.POST_OK, buildResourceChangesResponse(qResp, hitMaxRecords, reqBody.changeId, maxChangeId))
else (HttpCode.POST_OK, ResourceChangesRespObject(List[ChangeEntry](), maxChangeId, hitMaxRecords = false, ExchangeApi.adminVersion()))
}
Expand Down
109 changes: 109 additions & 0 deletions src/test/scala/exchangeapi/AgbotsSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,17 @@ class AgbotsSuite extends AnyFunSuite {
assert(parsedBody.changes.exists(y => {(y.id == agbotId) && (y.operation == ResourceChangeConfig.CREATEDMODIFIED)}))
}

test("POST /orgs/"+orgid+"/changes - verify " + agbotId + " can call notification framework") {
val time = ApiTime.pastUTC(secondsAgo)
val input = ResourceChangesRequest(0, Some(time), maxRecords, Some(List(orgid)))
val response = Http(URL+"/changes").postData(write(input)).method("post").headers(CONTENT).headers(ACCEPT).headers(AGBOTAUTH).asString
info("code: "+response.code)
assert(response.code === HttpCode.POST_OK.intValue)
assert(!response.body.isEmpty)
val parsedBody = parse(response.body).extract[ResourceChangesRespObject]
assert(parsedBody.changes.exists(y => {(y.id == agbotId) && (y.operation == ResourceChangeConfig.CREATEDMODIFIED)}))
}

/** Update normal agbot as user */
test("PUT /orgs/"+orgid+"/agbots/"+agbotId+" - normal - as user") {
val input = PutAgbotsRequest(agbotToken, "agbot"+agbotId+"-normal-user", None, "ABC")
Expand Down Expand Up @@ -980,6 +991,52 @@ class AgbotsSuite extends AnyFunSuite {
assert(parsedBody.maxChangeId > 0)
}

test("POST /orgs/"+orgid+"/changes - verify " + agbotId + " does not get wildcard case") {
val time = ApiTime.pastUTC(secondsAgo)
val input = ResourceChangesRequest(0, Some(time), maxRecords, Some(List("*")))
val response = Http(URL+"/changes").postData(write(input)).method("post").headers(CONTENT).headers(ACCEPT).headers(AGBOTAUTH).asString
info("code: "+response.code)
assert(response.code === HttpCode.POST_OK.intValue)
assert(!response.body.isEmpty)
val parsedBody = parse(response.body).extract[ResourceChangesRespObject]
assert(!parsedBody.changes.exists(y => {y.orgId == "IBM"}))
}

test("PUT /orgs/"+orgid+"/changes - with low maxRecords") {
if (runningLocally) { // changing limits via POST /admin/config does not work in multi-node mode
// Get the current config value so we can restore it afterward
ExchConfig.load()
val origMaxRecords = ExchConfig.getInt("api.resourceChanges.maxRecordsCap")
val newMaxRecords = 1
// Change the maxNodes config value in the svr
var configInput = AdminConfigRequest("api.resourceChanges.maxRecordsCap", newMaxRecords.toString)
var response = Http(NOORGURL+"/admin/config").postData(write(configInput)).method("put").headers(CONTENT).headers(ACCEPT).headers(ROOTAUTH).asString
info("code: "+response.code+", response.body: "+response.body)
assert(response.code === HttpCode.PUT_OK.intValue)

// Now post to /changes and make sure the size is respected even though maxRecords sent in is much higher
// NOTE maxRecords the variable must be larger than newMaxRecords
val time = ApiTime.pastUTC(secondsAgo)
val input = ResourceChangesRequest(0, Some(time), maxRecords, Some(List(orgid)))
response = Http(URL+"/changes").postData(write(input)).method("post").headers(CONTENT).headers(ACCEPT).headers(AGBOTAUTH).asString
info("code: "+response.code)
assert(response.code === HttpCode.POST_OK.intValue)
assert(!response.body.isEmpty)
val parsedBody = parse(response.body).extract[ResourceChangesRespObject]
info("parsedBody.changes.size: " + parsedBody.changes.size + " maxRecords: " + newMaxRecords)
assert(parsedBody.changes.size <= newMaxRecords)
assert(parsedBody.hitMaxRecords)

// Restore the maxNodes config value in the svr
configInput = AdminConfigRequest("api.resourceChanges.maxRecordsCap", origMaxRecords.toString)
response = Http(NOORGURL+"/admin/config").postData(write(configInput)).method("put").headers(CONTENT).headers(ACCEPT).headers(ROOTAUTH).asString
info("code: "+response.code+", response.body: "+response.body)
assert(response.code === HttpCode.PUT_OK.intValue)
val origMaxRecords2 = ExchConfig.getInt("api.resourceChanges.maxRecordsCap")
assert(origMaxRecords == origMaxRecords2)
}
}

/** Explicit delete of agbot */
test("DELETE /orgs/"+orgid+"/agbots/"+agbotId+" - as user") {
var response = Http(URL+"/agbots/"+agbotId).method("delete").headers(ACCEPT).headers(USERAUTH).asString
Expand All @@ -1002,6 +1059,58 @@ class AgbotsSuite extends AnyFunSuite {
assert(parsedBody.changes.exists(y => {(y.id == agbotId) && (y.operation == ResourceChangeConfig.DELETED) && (y.resource == "agbot")}))
}

test("POST /orgs/IBM/changes - as IBM agbot (if it exists)") {
val ibmAgbotAuth = sys.env.getOrElse("EXCHANGE_AGBOTAUTH", "")
val ibmAgbotId = """^[^:]+""".r.findFirstIn(ibmAgbotAuth).getOrElse("") // get the id before the :
info("ibmAgbotAuth="+ibmAgbotAuth+", ibmAgbotId="+ibmAgbotId+".")
if (ibmAgbotAuth != "") {
val IBMAGBOTAUTH = ("Authorization", "Basic " + ApiUtils.encode("IBM/" + ibmAgbotAuth))

// Notification Framework Tests
val time = ApiTime.pastUTC(secondsAgo)
var input = ResourceChangesRequest(0, Some(time), maxRecords, Some(List("*")))
var response = Http(urlRoot+"/v1/orgs/IBM/changes").postData(write(input)).method("post").headers(CONTENT).headers(ACCEPT).headers(IBMAGBOTAUTH).asString
info(urlRoot+"/v1/orgs/IBM/changes -- wildcard splat")
info("code: "+response.code)
assert(response.code === HttpCode.POST_OK.intValue)
assert(!response.body.isEmpty)
var parsedBody = parse(response.body).extract[ResourceChangesRespObject]
assert(parsedBody.changes.exists(y => {y.orgId == orgid}))
assert(parsedBody.changes.exists(y => {y.orgId == "IBM"}))

input = ResourceChangesRequest(0, Some(time), maxRecords, Some(List("")))
response = Http(urlRoot+"/v1/orgs/IBM/changes").postData(write(input)).method("post").headers(CONTENT).headers(ACCEPT).headers(IBMAGBOTAUTH).asString
info(urlRoot+"/v1/orgs/IBM/changes -- wildcard empty string")
info("code: "+response.code)
assert(response.code === HttpCode.POST_OK.intValue)
assert(!response.body.isEmpty)
parsedBody = parse(response.body).extract[ResourceChangesRespObject]
assert(parsedBody.changes.exists(y => {y.orgId == orgid}))
assert(parsedBody.changes.exists(y => {y.orgId == "IBM"}))

input = ResourceChangesRequest(0, Some(time), maxRecords, Some(List(orgid)))
response = Http(urlRoot+"/v1/orgs/IBM/changes").postData(write(input)).method("post").headers(CONTENT).headers(ACCEPT).headers(IBMAGBOTAUTH).asString
info(urlRoot+"/v1/orgs/IBM/changes -- orgList: ["+orgid+"]")
info("code: "+response.code)
assert(response.code === HttpCode.POST_OK.intValue)
assert(!response.body.isEmpty)
parsedBody = parse(response.body).extract[ResourceChangesRespObject]
assert(parsedBody.changes.exists(y => {y.orgId == orgid}))
assert(!parsedBody.changes.exists(y => {y.orgId == "IBM"}))

input = ResourceChangesRequest(0, Some(time), maxRecords, Some(List("IBM")))
response = Http(urlRoot+"/v1/orgs/IBM/changes").postData(write(input)).method("post").headers(CONTENT).headers(ACCEPT).headers(IBMAGBOTAUTH).asString
info(urlRoot+"/v1/orgs/IBM/changes -- orgList: [\"IBM\"]")
info("code: "+response.code)
assert(response.code === HttpCode.POST_OK.intValue)
assert(!response.body.isEmpty)
parsedBody = parse(response.body).extract[ResourceChangesRespObject]
assert(!parsedBody.changes.exists(y => {y.orgId == orgid}))
assert(parsedBody.changes.exists(y => {y.orgId == "IBM"}))

}
}

// Note: testing of msgs is in NodesSuite.scala

/** Clean up, delete all the test agbots */
Expand Down

0 comments on commit 50246d6

Please sign in to comment.