Unifying simple & complex resources.
[aquarium] / src / test / scala / gr / grnet / aquarium / user / UserStateComputationsTest.scala
1 package gr.grnet.aquarium.user
2
3 import org.junit.Test
4 import gr.grnet.aquarium.Configurator
5 import gr.grnet.aquarium.store.memory.MemStore
6 import gr.grnet.aquarium.util.date.MutableDateCalc
7 import gr.grnet.aquarium.logic.accounting.dsl._
8 import gr.grnet.aquarium.logic.accounting.{Policy, Accounting}
9 import gr.grnet.aquarium.util.{Loggable, ContextualLogger}
10 import com.ckkloverdos.maybe.{Just, NoVal}
11 import gr.grnet.aquarium.simulation._
12 import gr.grnet.aquarium.simulation.uid.{UIDGenerator, ConcurrentVMLocalUIDGenerator}
13
14
15 /**
16  *
17  * @author Christos KK Loverdos <loverdos@gmail.com>
18  */
19 class UserStateComputationsTest extends Loggable {
20   val PolicyYAML = """
21 aquariumpolicy:
22   resources:
23     - resource:
24       name: bandwidth
25       unit: MB/hr
26       complex: false
27       costpolicy: discrete
28     - resource:
29       name: vmtime
30       unit: Hour
31       complex: true
32       costpolicy: onoff
33       descriminatorfield: vmid
34     - resource:
35       name: diskspace
36       unit: MB/hr
37       complex: false
38       costpolicy: continuous
39
40   implicitvars:
41     - price
42     - volume
43
44   algorithms:
45     - algorithm:
46       name: default
47       bandwidth: function bandwidth() {return 1;}
48       vmtime: function vmtime() {return 1;}
49       diskspace: function diskspace() {return 1;}
50       effective:
51         from: 0
52
53   pricelists:
54     - pricelist:
55       name: default
56       bandwidth: 1.0
57       vmtime: 1.0
58       diskspace: 1.0
59       effective:
60         from: 0
61
62   creditplans:
63     - creditplan:
64       name: default
65       credits: 100
66       at: "00 00 1 * *"
67       effective:
68         from: 0
69
70   agreements:
71     - agreement:
72       name: default
73       algorithm: default
74       pricelist: default
75       creditplan: default
76   """
77
78   val DefaultPolicy = new DSL{} parse PolicyYAML
79
80   // TODO: integrate this with the rest of the simulation stuff
81   // TODO: since, right now, the resource strings have to be given twice
82   val VMTimeResource    = StdVMTimeResourceSim
83   val DiskspaceResource = StdDiskspaceResourceSim
84   val BandwidthResource = StdBandwidthResourceSim
85
86   // There are two client services, synnefo and pithos.
87   val TheUIDGenerator: UIDGenerator = new ConcurrentVMLocalUIDGenerator
88   val Synnefo = ClientSim("synnefo")(TheUIDGenerator)
89   val Pithos  = ClientSim("pithos" )(TheUIDGenerator)
90
91   @Test
92   def testOne: Unit = {
93     val clog = ContextualLogger.fromOther(NoVal, logger, "testOne()")
94     val StartOfBillingYearDateCalc = new MutableDateCalc(2012,  1, 1)
95     val UserCreationDate           = new MutableDateCalc(2011, 11, 1).toDate
96
97     val computations = new UserStateComputations
98
99     val mc = Configurator.MasterConfigurator.withStoreProviderClass(classOf[MemStore])
100     Policy.withConfigurator(mc)
101
102     val storeProvider = mc.storeProvider
103     val userStateStore = storeProvider.userStateStore
104     val resourceEventStore = storeProvider.resourceEventStore
105     val policyStore = storeProvider.policyStore
106
107     // Store the default policy
108     val policyDateCalc        = StartOfBillingYearDateCalc.copy
109     val policyOccurredMillis  = policyDateCalc.toMillis
110     val policyValidFromMillis = policyDateCalc.copy.goPreviousYear.toMillis
111     val policyValidToMillis   = policyDateCalc.copy.goNextYear.toMillis
112     policyStore.storePolicyEntry(DefaultPolicy.toPolicyEntry(policyOccurredMillis, policyValidFromMillis, policyValidToMillis))
113
114     val Aquarium = AquariumSim(List(VMTimeResource, DiskspaceResource, BandwidthResource), storeProvider.resourceEventStore)
115     val DefaultResourcesMap = Aquarium.resourcesMap
116
117     // A new user is created on 2012-01-15 00:00:00.000
118     val UserCKKL  = Aquarium.newUser("CKKL", UserCreationDate)
119
120     // By convention
121     // - synnefo is for VMTime and Bandwidth
122     // - pithos is for Diskspace
123     val VMTimeInstance    = StdVMTimeInstanceSim   ("VM.1",   UserCKKL, Synnefo)
124     val BandwidthInstance = StdBandwidthInstanceSim("3G.1",   UserCKKL, Synnefo)
125     val DiskInstance      = StdDiskspaceInstanceSim("DISK.1", UserCKKL, Pithos)
126
127     // Let's create our dates of interest
128     val vmStartDateCalc = StartOfBillingYearDateCalc.copy.goPlusDays(1).goPlusHours(1)
129     val vmStartDate = vmStartDateCalc.toDate
130
131     // Within January, create one VM ON-OFF ...
132     VMTimeInstance.newONOFF(vmStartDate, 9)
133
134     val diskConsumptionDateCalc = StartOfBillingYearDateCalc.copy.goPlusHours(3)
135     val diskConsumptionDate1 = diskConsumptionDateCalc.toDate
136     val diskConsumptionDateCalc2 = diskConsumptionDateCalc.copy.goPlusDays(1).goPlusHours(1)
137     val diskConsumptionDate2 = diskConsumptionDateCalc2.toDate
138
139     // ... and two diskspace changes
140     DiskInstance.consumeMB(diskConsumptionDate1, 99)
141     DiskInstance.consumeMB(diskConsumptionDate2, 23)
142
143     // 100MB 3G bandwidth
144     val bwDateCalc = diskConsumptionDateCalc2.copy.goPlusDays(1)
145     BandwidthInstance.useBandwidth(bwDateCalc.toDate, 100.0)
146
147     // ... and one "future" event
148     DiskInstance.consumeMB(
149       StartOfBillingYearDateCalc.copy.
150         goNextMonth.goPlusDays(6).
151         goPlusHours(7).
152         goPlusMinutes(7).
153         goPlusSeconds(7).
154         goPlusMillis(7).toDate,
155       777)
156
157     clog.debug("")
158     clog.begin("Events by OccurredMillis")
159     clog.withIndent {
160       for(event <- UserCKKL.myResourceEventsByOccurredDate) {
161         clog.debug(event.toDebugString(DefaultResourcesMap))
162       }
163     }
164     clog.end("Events by OccurredMillis")
165     clog.debug("")
166
167     val billingMonthInfo = BillingMonthInfo.fromDateCalc(StartOfBillingYearDateCalc)
168
169     val initialUserState = computations.createFirstUserState(
170       userId = UserCKKL.userId,
171       userCreationMillis = UserCreationDate.getTime,
172       isActive = true,
173       credits = 0.0,
174       roleNames = List("user"),
175       agreementName = DSLAgreement.DefaultAgreementName
176     )
177
178     val currentUserState = initialUserState
179
180     // Policy: from 2012-01-01 to Infinity
181
182     clog.debugMap("DefaultResourcesMap", DefaultResourcesMap.map, 1)
183
184     val userStateM = computations.doFullMonthlyBilling(
185       UserCKKL.userId,
186       billingMonthInfo,
187       userStateStore,
188       resourceEventStore,
189       policyStore,
190       UserCKKL.userCreationDate.getTime,
191       currentUserState,
192       initialUserState,
193       DefaultResourcesMap,
194       new Accounting{},
195       Just(clog)
196     )
197     
198     clog.debug("userStateM = %s".format(userStateM))
199     userStateM.forFailed { failed ⇒
200       clog.error(failed)
201       failed.exception.printStackTrace()
202       NoVal
203     }
204   }
205 }