#  Licensed under the Apache License, Version 2.0 (the "License"); you may
#  not use this file except in compliance with the License. You may obtain
#  a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#  License for the specific language governing permissions and limitations
#  under the License.

Namespaces:
  =: io.murano.applications.tests
  tst: io.murano.test
  std: io.murano
  apps: io.murano.applications

--- # ------------------------------------------------------------------ # ---

Name: Replica

Properties:
  name:
    Contract: $.string()

--- # ------------------------------------------------------------------ # ---

Name: DummyReplicaProvider
Extends: apps:ReplicaProvider

Properties:
  allocated:
    Usage: InOut
    Contract: $.int()
    Default: 0

Methods:
  createReplica:
    Arguments:
      - index:
         Contract: $.int()
      - owner:
         Contract: $.class(std:Object)
    Body:
      - $replica: new(Replica, name => format('replica-{0}', $index))
      - $this.allocated: $this.allocated + 1
      - Return: $replica

  releaseReplicas:
    Arguments:
      replicas:
        Contract:
          - $
    Body:
      - $this.allocated: $this.allocated - len($replicas)


--- # ------------------------------------------------------------------ # ---

Name: TestReplication
Extends: tst:TestFixture

Methods:
  setUp:
    Body:
      - $this.provider: new(DummyReplicaProvider)

  testCreateDefault:
    Body:
      - $group: new(apps:ReplicationGroup, provider => $this.provider)
      - $group.deploy()
      - $.assertEqual(1, len($group.items))
      - $.assertEqual(1, $this.provider.allocated)
      - $.assertEqual('replica-1', $group.items[0].name)

  testCreateMultiple:
    Body:
      - $group: new(apps:ReplicationGroup, provider => $this.provider, numItems => 5)
      - $group.deploy()
      - $.assertEqual(5, len($group.items))


  testScale:
    Body:
      - $group: new(apps:ReplicationGroup, provider => $this.provider)
      - $group.deploy()
      - $.assertEqual(1, len($group.items))
      - $group.scale(1)
      - $.assertEqual(2, len($group.items))
      - $.assertEqual(2, $this.provider.allocated)
      - $group.scale(-1)
      - $.assertEqual(1, len($group.items))
      - $.assertEqual(1, $this.provider.allocated)

--- # ------------------------------------------------------------------ # ---

Name: TestPoolReplicaProvider
Extends: tst:TestFixture

Methods:
  setUp:
    Body:
      - $this.object1: new(std:Object)
      - $this.object2: new(std:Object)
      - $this.provider: new(apps:PoolReplicaProvider, pool => [$this.object1, $this.object2])

  testReplicas:
    Body:
      - $.assertEqual(2, len($this.provider.pool))
      - $.assertEqual(0, len($this.provider.consumedItems))
      - $obj: $this.provider.createReplica(1, $this)
      - $.assertEqual($this.object1, $obj)
      - $.assertEqual(2, len($this.provider.pool))
      - $.assertEqual(1, len($this.provider.consumedItems))
      - $obj: $this.provider.createReplica(2, $this)
      - $.assertEqual($this.object2, $obj)
      - $.assertEqual(2, len($this.provider.pool))
      - $.assertEqual(2, len($this.provider.consumedItems))
      - $obj: $this.provider.createReplica(3, $this)
      - $.assertEqual(null, $obj)
      - $.assertEqual(2, len($this.provider.pool))
      - $.assertEqual(2, len($this.provider.consumedItems))

  testReleaseReplicas:
    Body:
      - $obj: $this.provider.createReplica(1, $this)
      - $.assertEqual(1, len($this.provider.consumedItems))
      - $foreignObj: new(std:Object)
      - $res: $this.provider.releaseReplicas([$obj, $this.object1, $this.object2, $foreignObj])
      - $.assertEqual(0, len($this.provider.consumedItems))
      - $.assertEqual([$this.object2, $foreignObj], $res)
      - $this.testReplicas()

--- # ------------------------------------------------------------------ # ---

Name: TestRoundrobinReplicaProvider
Extends: tst:TestFixture

Methods:
  setUp:
    Body:
      - $this.object1: new(std:Object)
      - $this.object2: new(std:Object)
      - $this.provider: new(apps:RoundrobinReplicaProvider, items => [$this.object1, $this.object2])

  testReplicas:
    Body:
      - $obj: $this.provider.createReplica(1, $this)
      - $.assertEqual($this.object1, $obj)
      - $obj: $this.provider.createReplica(2, $this)
      - $.assertEqual($this.object2, $obj)
      - $obj: $this.provider.createReplica(3, $this)
      - $.assertEqual($this.object1, $obj)
      - $obj: $this.provider.createReplica(4, $this)
      - $.assertEqual($this.object2, $obj)

--- # ------------------------------------------------------------------ # ---

Name: TestCompositeReplicaProvider
Extends: tst:TestFixture

Methods:
  setUp:
    Body:
      - $this.objects: range(4).select(new(std:Object))
      - $this.object2: new(std:Object)
      - $this.provider1: new(apps:PoolReplicaProvider, pool => [$this.objects[0], $this.objects[1]])
      - $this.provider2: new(apps:RoundrobinReplicaProvider, items => [$this.objects[2], $this.objects[3]])
      - $this.provider: new(apps:CompositeReplicaProvider, providers => [$this.provider1, $this.provider2])

  testReplicas:
    Body:
      - $obj: $this.provider.createReplica(1, $this)
      - $.assertEqual($this.objects[0], $obj)
      - $obj: $this.provider.createReplica(2, $this)
      - $.assertEqual($this.objects[1], $obj)
      - $obj: $this.provider.createReplica(3, $this)
      - $.assertEqual($this.objects[2], $obj)
      - $obj: $this.provider.createReplica(4, $this)
      - $.assertEqual($this.objects[3], $obj)
      - $obj: $this.provider.createReplica(5, $this)
      - $.assertEqual($this.objects[2], $obj)
